diff --git a/binding.gyp b/binding.gyp index 249e9e82..fe1509ba 100644 --- a/binding.gyp +++ b/binding.gyp @@ -3,7 +3,11 @@ { "target_name": "superstring", "dependencies": [ - "superstring_core" + "superstring_core", + " resolve(this.findSync(pattern))) - } - - TextBuffer.prototype.findInRange = function (pattern, range) { - return new Promise(resolve => resolve(this.findInRangeSync(pattern, range))) - } - - TextBuffer.prototype.findAll = function (pattern) { - return new Promise(resolve => resolve(this.findAllSync(pattern))) - } - - TextBuffer.prototype.findAllInRange = function (pattern, range) { - return new Promise(resolve => resolve(this.findAllInRangeSync(pattern, range))) - } - - TextBuffer.prototype.findWordsWithSubsequence = function (query, extraWordCharacters, maxCount) { - const range = {start: {row: 0, column: 0}, end: this.getExtent()} - return Promise.resolve( - findWordsWithSubsequenceInRange.call(this, query, extraWordCharacters, range).slice(0, maxCount) - ) - } - - TextBuffer.prototype.findWordsWithSubsequenceInRange = function (query, extraWordCharacters, maxCount, range) { - return Promise.resolve( - findWordsWithSubsequenceInRange.call(this, query, extraWordCharacters, range).slice(0, maxCount) - ) - } - - TextBuffer.prototype.getCharacterAtPosition = function (position) { - return String.fromCharCode(getCharacterAtPosition.call(this, position)) +try { + binding = require('./build/Release/superstring.node') +} catch (e1) { + try { + binding = require('./build/Debug/superstring.node') + } catch (e2) { + throw e1 } +} - const {compose} = Patch - const {splice} = Patch.prototype - - Patch.compose = function (patches) { - const result = compose.call(this, patches) - if (!result) throw new Error('Patch does not apply') - return result - } +const {TextBuffer, TextWriter, TextReader} = binding - Patch.prototype.splice = Object.assign(function () { - if (!splice.apply(this, arguments)) { - throw new Error('Patch does not apply') - } - }, splice) -} else { - try { - binding = require('./build/Release/superstring.node') - } catch (e1) { - try { - binding = require('./build/Debug/superstring.node') - } catch (e2) { - throw e1 - } +TextBuffer.prototype.load = function (source, options, progressCallback) { + if (typeof options !== 'object') { + progressCallback = options + options = {} } - const {TextBuffer, TextWriter, TextReader} = binding - const { - load, save, baseTextMatchesFile, - find, findAll, findSync, findAllSync, findWordsWithSubsequenceInRange - } = TextBuffer.prototype + const computePatch = options.patch === false ? false : true + const discardChanges = options.force === true ? true : false + const encoding = normalizeEncoding(options.encoding || 'UTF-8') - TextBuffer.prototype.load = function (source, options, progressCallback) { - if (typeof options !== 'object') { - progressCallback = options - options = {} + return new Promise((resolve, reject) => { + const completionCallback = (error, result) => { + error ? reject(error) : resolve(result) } - const computePatch = options.patch === false ? false : true - const discardChanges = options.force === true ? true : false - const encoding = normalizeEncoding(options.encoding || 'UTF-8') - - return new Promise((resolve, reject) => { - const completionCallback = (error, result) => { - error ? reject(error) : resolve(result) - } - - if (typeof source === 'string') { - const filePath = source - load.call( - this, + if (typeof source === 'string') { + const filePath = source + this._load( + completionCallback, + progressCallback, + discardChanges, + computePatch, + filePath, + encoding + ) + } else { + const stream = source + const writer = new TextWriter(encoding) + stream.on('data', (data) => writer.write(data)) + stream.on('error', reject) + stream.on('end', () => { + writer.end() + this._load( completionCallback, progressCallback, discardChanges, computePatch, - filePath, - encoding + writer ) - } else { - const stream = source - const writer = new TextWriter(encoding) - stream.on('data', (data) => writer.write(data)) - stream.on('error', reject) - stream.on('end', () => { - writer.end() - load.call( - this, - completionCallback, - progressCallback, - discardChanges, - computePatch, - writer - ) - }) - } - }) - } - - TextBuffer.prototype.save = function (destination, encoding = 'UTF8') { - const CHUNK_SIZE = 10 * 1024 + }) + } + }) +} - encoding = normalizeEncoding(encoding) +TextBuffer.prototype.save = function (destination, encoding = 'UTF8') { + const CHUNK_SIZE = 10 * 1024 - return new Promise((resolve, reject) => { - if (typeof destination === 'string') { - const filePath = destination - save.call(this, filePath, encoding, (error) => { - error ? reject(error) : resolve() - }) - } else { - const stream = destination - const reader = new TextReader(this, encoding) - const buffer = Buffer.allocUnsafe(CHUNK_SIZE) - writeToStream(null) + encoding = normalizeEncoding(encoding) - stream.on('error', (error) => { - reader.destroy() - reject(error) - }) + return new Promise((resolve, reject) => { + if (typeof destination === 'string') { + const filePath = destination + this._save(filePath, encoding, (error) => { + error ? reject(error) : resolve() + }) + } else { + const stream = destination + const reader = new TextReader(this, encoding) + const buffer = Buffer.allocUnsafe(CHUNK_SIZE) + writeToStream(null) + + stream.on('error', (error) => { + reader.destroy() + reject(error) + }) - function writeToStream () { - const bytesRead = reader.read(buffer) - if (bytesRead > 0) { - stream.write(buffer.slice(0, bytesRead), (error) => { - if (!error) writeToStream() - }) - } else { - stream.end(() => { - reader.end() - resolve() - }) - } + function writeToStream () { + const bytesRead = reader.read(buffer) + if (bytesRead > 0) { + stream.write(buffer.slice(0, bytesRead), (error) => { + if (!error) writeToStream() + }) + } else { + stream.end(() => { + reader.end() + resolve() + }) } } - }) - } - - TextBuffer.prototype.find = function (pattern) { - return this.findInRange(pattern, null) - } + } + }) +} - TextBuffer.prototype.findInRange = function (pattern, range) { - return new Promise((resolve, reject) => { - find.call(this, pattern, (error, result) => { - error ? reject(error) : resolve(result.length > 0 ? interpretRange(result) : null) - }, range) - }) - } +TextBuffer.prototype.find = function (pattern) { + return this.findInRange(pattern, null) +} - TextBuffer.prototype.findAll = function (pattern) { - return this.findAllInRange(pattern, null) - } +TextBuffer.prototype.findInRange = function (pattern, range) { + return new Promise((resolve, reject) => { + this._find(pattern, (error, result) => { + error ? reject(error) : resolve(result.length > 0 ? interpretRange(result) : null) + }, range) + }) +} - TextBuffer.prototype.findAllInRange = function (pattern, range) { - return new Promise((resolve, reject) => { - findAll.call(this, pattern, (error, result) => { - error ? reject(error) : resolve(interpretRangeArray(result)) - }, range) - }) - } +TextBuffer.prototype.findAll = function (pattern) { + return this.findAllInRange(pattern, null) +} - TextBuffer.prototype.findSync = function (pattern) { - return this.findInRangeSync(pattern, null) - } +TextBuffer.prototype.findAllInRange = function (pattern, range) { + return new Promise((resolve, reject) => { + this._findAll(pattern, (error, result) => { + error ? reject(error) : resolve(interpretRangeArray(result)) + }, range) + }) +} - TextBuffer.prototype.findInRangeSync = function (pattern, range) { - const result = findSync.call(this, pattern, range) - return result.length > 0 ? interpretRange(result) : null - } +TextBuffer.prototype.findSync = function (pattern) { + return this.findInRangeSync(pattern, null) +} - TextBuffer.prototype.findAllSync = function (pattern) { - return interpretRangeArray(findAllSync.call(this, pattern, null)) - } +TextBuffer.prototype.findInRangeSync = function (pattern, range) { + const result = this._findSync(pattern, range) + return result.length > 0 ? interpretRange(result) : null +} - TextBuffer.prototype.findAllInRangeSync = function (pattern, range) { - return interpretRangeArray(findAllSync.call(this, pattern, range)) - } +TextBuffer.prototype.findAllSync = function (pattern) { + return interpretRangeArray(this._findAllSync(pattern, null)) +} - TextBuffer.prototype.findWordsWithSubsequence = function (query, extraWordCharacters, maxCount) { - return this.findWordsWithSubsequenceInRange(query, extraWordCharacters, maxCount, { - start: {row: 0, column: 0}, - end: this.getExtent() - }) - } +TextBuffer.prototype.findAllInRangeSync = function (pattern, range) { + return interpretRangeArray(this._findAllSync(pattern, range)) +} - TextBuffer.prototype.findWordsWithSubsequenceInRange = function (query, extraWordCharacters, maxCount, range) { - return new Promise(resolve => - findWordsWithSubsequenceInRange.call(this, query, extraWordCharacters, maxCount, range, (matches, positions) => { - if (!matches) { - resolve(null) - return - } +TextBuffer.prototype.findWordsWithSubsequence = function (query, extraWordCharacters, maxCount) { + return this.findWordsWithSubsequenceInRange(query, extraWordCharacters, maxCount, { + start: {row: 0, column: 0}, + end: this.getExtent() + }) +} - let positionArrayIndex = 0 - for (let i = 0, n = matches.length; i < n; i++) { - let positionCount = positions[positionArrayIndex++] - matches[i].positions = interpretPointArray(positions, positionArrayIndex, positionCount) - positionArrayIndex += 2 * positionCount - } - resolve(matches) - }) - ) - } +TextBuffer.prototype.findWordsWithSubsequenceInRange = function (query, extraWordCharacters, maxCount, range) { + return new Promise(resolve => + this._findWordsWithSubsequenceInRange(query, extraWordCharacters, maxCount, range, (matches, positions) => { + if (!matches) { + resolve(null) + return + } - TextBuffer.prototype.baseTextMatchesFile = function (source, encoding = 'UTF8') { - return new Promise((resolve, reject) => { - const callback = (error, result) => { - if (error) { - reject(error) - } else { - resolve(result) - } + let positionArrayIndex = 0 + for (let i = 0, n = matches.length; i < n; i++) { + let positionCount = positions[positionArrayIndex++] + matches[i].positions = interpretPointArray(positions, positionArrayIndex, positionCount) + positionArrayIndex += 2 * positionCount } + resolve(matches) + }) + ) +} - if (typeof source === 'string') { - baseTextMatchesFile.call(this, callback, source, encoding) +TextBuffer.prototype.baseTextMatchesFile = function (source, encoding = 'UTF8') { + return new Promise((resolve, reject) => { + const callback = (error, result) => { + if (error) { + reject(error) } else { - const stream = source - const writer = new TextWriter(encoding) - stream.on('data', (data) => writer.write(data)) - stream.on('error', reject) - stream.on('end', () => { - writer.end() - baseTextMatchesFile.call(this, callback, writer) - }) + resolve(result) } - }) - } + } - function interpretPointArray (rawData, startIndex, pointCount) { - const points = [] - for (let i = 0; i < pointCount; i++) { - points.push({row: rawData[startIndex++], column: rawData[startIndex++]}) + if (typeof source === 'string') { + this._baseTextMatchesFile(callback, source, encoding) + } else { + const stream = source + const writer = new TextWriter(encoding) + stream.on('data', (data) => writer.write(data)) + stream.on('error', reject) + stream.on('end', () => { + writer.end() + this._baseTextMatchesFile(callback, writer) + }) } - return points + }) +} + +function interpretPointArray (rawData, startIndex, pointCount) { + const points = [] + for (let i = 0; i < pointCount; i++) { + points.push({row: rawData[startIndex++], column: rawData[startIndex++]}) } + return points +} - function interpretRangeArray (rawData) { - const rangeCount = rawData.length / 4 - const ranges = new Array(rangeCount) - let rawIndex = 0 - for (let rangeIndex = 0; rangeIndex < rangeCount; rangeIndex++) { - ranges[rangeIndex] = interpretRange(rawData, rawIndex) - rawIndex += 4 - } - return ranges +function interpretRangeArray (rawData) { + const rangeCount = rawData.length / 4 + const ranges = new Array(rangeCount) + let rawIndex = 0 + for (let rangeIndex = 0; rangeIndex < rangeCount; rangeIndex++) { + ranges[rangeIndex] = interpretRange(rawData, rawIndex) + rawIndex += 4 } + return ranges +} - function interpretRange (rawData, index = 0) { - return { - start: { - row: rawData[index], - column: rawData[index + 1] - }, - end: { - row: rawData[index + 2], - column: rawData[index + 3] - } +function interpretRange (rawData, index = 0) { + return { + start: { + row: rawData[index], + column: rawData[index + 1] + }, + end: { + row: rawData[index + 2], + column: rawData[index + 3] } } -} + } function normalizeEncoding(encoding) { return encoding.toUpperCase() diff --git a/package.json b/package.json index d5df9424..0a848e0b 100644 --- a/package.json +++ b/package.json @@ -5,13 +5,9 @@ "main": "./index", "browser": "./browser", "scripts": { - "build:node": "node-gyp rebuild", - "build:browser": "script/build-browser-version.sh", - "build": "npm run build:node && npm run build:browser", + "build": "node-gyp rebuild", "test:native": "node ./script/test-native.js", - "test:node": "mocha test/js/*.js", - "test:browser": "SUPERSTRING_USE_BROWSER_VERSION=1 mocha test/js/*.js", - "test": "npm run test:node && npm run test:browser", + "test": "mocha test/js/*.js", "benchmark": "node benchmark/marker-index.benchmark.js", "prepublishOnly": "git submodule update --init --recursive && npm run build:browser", "standard": "standard --recursive src test" @@ -31,7 +27,8 @@ }, "homepage": "https://github.com/atom/superstring", "dependencies": { - "nan": "^2.14.2" + "nan": "^2.14.2", + "node-addon-api": "^5.0.0" }, "devDependencies": { "chai": "^2.0.0", diff --git a/script/build-browser-version.sh b/script/build-browser-version.sh deleted file mode 100755 index bb370e11..00000000 --- a/script/build-browser-version.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env bash - -source emsdk-portable/emsdk_env.sh - -mkdir -p build - -emcc \ - -o build/pcre.o \ - -O3 \ - -I vendor/pcre/10.23/src \ - -I vendor/pcre/include \ - -D HAVE_CONFIG_H \ - -D PCRE2_CODE_UNIT_WIDTH=16 \ - vendor/pcre/pcre2_chartables.c \ - vendor/pcre/10.23/src/pcre2_auto_possess.c \ - vendor/pcre/10.23/src/pcre2_compile.c \ - vendor/pcre/10.23/src/pcre2_config.c \ - vendor/pcre/10.23/src/pcre2_context.c \ - vendor/pcre/10.23/src/pcre2_dfa_match.c \ - vendor/pcre/10.23/src/pcre2_error.c \ - vendor/pcre/10.23/src/pcre2_find_bracket.c \ - vendor/pcre/10.23/src/pcre2_jit_compile.c \ - vendor/pcre/10.23/src/pcre2_maketables.c \ - vendor/pcre/10.23/src/pcre2_match.c \ - vendor/pcre/10.23/src/pcre2_match_data.c \ - vendor/pcre/10.23/src/pcre2_newline.c \ - vendor/pcre/10.23/src/pcre2_ord2utf.c \ - vendor/pcre/10.23/src/pcre2_pattern_info.c \ - vendor/pcre/10.23/src/pcre2_serialize.c \ - vendor/pcre/10.23/src/pcre2_string_utils.c \ - vendor/pcre/10.23/src/pcre2_study.c \ - vendor/pcre/10.23/src/pcre2_substitute.c \ - vendor/pcre/10.23/src/pcre2_substring.c \ - vendor/pcre/10.23/src/pcre2_tables.c \ - vendor/pcre/10.23/src/pcre2_ucd.c \ - vendor/pcre/10.23/src/pcre2_valid_utf.c \ - vendor/pcre/10.23/src/pcre2_xclass.c - -em++ \ - --bind \ - -o browser.js \ - -O3 \ - -I src/bindings/em \ - -I src/core \ - -I vendor/libcxx \ - -I vendor/pcre/include \ - -D PCRE2_CODE_UNIT_WIDTH=16 \ - -xc++ \ - --pre-js src/bindings/em/prologue.js \ - --post-js src/bindings/em/epilogue.js \ - src/core/*.cc \ - src/bindings/em/*.cc \ - build/pcre.o \ - -s TOTAL_MEMORY=134217728 \ - --memory-init-file 0 \ - "$@" diff --git a/script/install-emscripten.sh b/script/install-emscripten.sh deleted file mode 100755 index 952cbcd4..00000000 --- a/script/install-emscripten.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -set -e - -EMSCRIPTEN_DOWNLOAD_URL='https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz' -EMSDK_PATH="./emsdk-portable/emsdk" - -if [ ! -f $EMSDK_PATH ]; then - echo 'Downloading emscripten SDK installer...' - curl $EMSCRIPTEN_DOWNLOAD_URL | tar xz -fi - -echo 'Installing emscripten SDK...' - -# Workaround https://github.com/juj/emsdk/pull/74 -sed -i{} "s_/kripken/emscripten/'_/kripken/emscripten'_" $EMSDK_PATH -sed -i{} "s_/WebAssembly/binaryen/'_/WebAssembly/binaryen'_" $EMSDK_PATH - -$EMSDK_PATH update -$EMSDK_PATH list -$EMSDK_PATH install sdk-1.37.9-64bit -$EMSDK_PATH activate sdk-1.37.9-64bit diff --git a/src/bindings/bindings.cc b/src/bindings/bindings.cc index fc9b31e1..29308002 100644 --- a/src/bindings/bindings.cc +++ b/src/bindings/bindings.cc @@ -1,24 +1,42 @@ +#include #include "marker-index-wrapper.h" -#include "nan.h" #include "patch-wrapper.h" #include "range-wrapper.h" #include "point-wrapper.h" -#include "text-writer.h" -#include "text-reader.h" -#include "text-buffer-wrapper.h" -#include "text-buffer-snapshot-wrapper.h" +// #include "text-writer.h" +// #include "text-reader.h" +// #include "text-buffer-wrapper.h" +// #include "text-buffer-snapshot-wrapper.h" -using namespace v8; +// FIXME: Remove NAN +// using namespace v8; -void Init(Local exports) { - PointWrapper::init(); - RangeWrapper::init(); - PatchWrapper::init(exports); - MarkerIndexWrapper::init(exports); - TextBufferWrapper::init(exports); - TextWriter::init(exports); - TextReader::init(exports); - TextBufferSnapshotWrapper::init(); +// void Init(Local exports) { +// PointWrapper::init(); +// RangeWrapper::init(); +// PatchWrapper::init(exports); +// MarkerIndexWrapper::init(exports); +// TextBufferWrapper::init(exports); +// TextWriter::init(exports); +// TextReader::init(exports); +// TextBufferSnapshotWrapper::init(); +// } +// +// NAN_MODULE_WORKER_ENABLED(superstring, Init) + +// using namespace Napi; +// static Object NAPI_Init(Env env, Object exports) { +// return exports; +// } + +// NODE_MODULE_INITIALIZER(NODE_GYP_MODULE_NAME, exports); + +Napi::Object InitNapi(Napi::Env env, Napi::Object exports) { + PointWrapper::init(env, exports); + RangeWrapper::init(env, exports); + PatchWrapper::init(env, exports); + MarkerIndexWrapper::init(env, exports); + return exports; } -NODE_MODULE(superstring, Init) +NODE_API_MODULE(NODE_GYP_MODULE_NAME, InitNapi); diff --git a/src/bindings/marker-index-wrapper.cc b/src/bindings/marker-index-wrapper.cc index f53853e3..58ae81a2 100644 --- a/src/bindings/marker-index-wrapper.cc +++ b/src/bindings/marker-index-wrapper.cc @@ -1,384 +1,401 @@ #include "marker-index-wrapper.h" #include #include "marker-index.h" -#include "nan.h" -#include "noop.h" #include "optional.h" #include "point-wrapper.h" #include "range.h" -using namespace v8; -using std::unordered_map; - -static Nan::Persistent marker_index_constructor_template; -static Nan::Persistent start_string; -static Nan::Persistent end_string; -static Nan::Persistent touch_string; -static Nan::Persistent inside_string; -static Nan::Persistent overlap_string; -static Nan::Persistent surround_string; -static Nan::Persistent containing_start_string; -static Nan::Persistent boundaries_string; -static Nan::Persistent position_string; -static Nan::Persistent starting_string; -static Nan::Persistent ending_string; - -void MarkerIndexWrapper::init(Local exports) { - Local constructor_template = Nan::New(construct); - constructor_template->SetClassName(Nan::New("MarkerIndex").ToLocalChecked()); - constructor_template->InstanceTemplate()->SetInternalFieldCount(1); - - const auto &prototype_template = constructor_template->PrototypeTemplate(); - - Nan::SetTemplate(prototype_template, Nan::New("delete").ToLocalChecked(), Nan::New(noop), None); - Nan::SetTemplate(prototype_template, Nan::New("generateRandomNumber").ToLocalChecked(), - Nan::New(generate_random_number), None); - Nan::SetTemplate(prototype_template, Nan::New("insert").ToLocalChecked(), Nan::New(insert), None); - Nan::SetTemplate(prototype_template, Nan::New("setExclusive").ToLocalChecked(), Nan::New(set_exclusive), None); - Nan::SetTemplate(prototype_template, Nan::New("remove").ToLocalChecked(), Nan::New(remove), None); - Nan::SetTemplate(prototype_template, Nan::New("has").ToLocalChecked(), Nan::New(has), None); - Nan::SetTemplate(prototype_template, Nan::New("splice").ToLocalChecked(), Nan::New(splice), None); - Nan::SetTemplate(prototype_template, Nan::New("getStart").ToLocalChecked(), Nan::New(get_start), None); - Nan::SetTemplate(prototype_template, Nan::New("getEnd").ToLocalChecked(), Nan::New(get_end), None); - Nan::SetTemplate(prototype_template, Nan::New("getRange").ToLocalChecked(), Nan::New(get_range), None); - Nan::SetTemplate(prototype_template, Nan::New("compare").ToLocalChecked(), Nan::New(compare), None); - Nan::SetTemplate(prototype_template, Nan::New("findIntersecting").ToLocalChecked(), - Nan::New(find_intersecting), None); - Nan::SetTemplate(prototype_template, Nan::New("findContaining").ToLocalChecked(), - Nan::New(find_containing), None); - Nan::SetTemplate(prototype_template, Nan::New("findContainedIn").ToLocalChecked(), - Nan::New(find_contained_in), None); - Nan::SetTemplate(prototype_template, Nan::New("findStartingIn").ToLocalChecked(), - Nan::New(find_starting_in), None); - Nan::SetTemplate(prototype_template, Nan::New("findStartingAt").ToLocalChecked(), - Nan::New(find_starting_at), None); - Nan::SetTemplate(prototype_template, Nan::New("findEndingIn").ToLocalChecked(), Nan::New(find_ending_in), None); - Nan::SetTemplate(prototype_template, Nan::New("findEndingAt").ToLocalChecked(), Nan::New(find_ending_at), None); - Nan::SetTemplate(prototype_template, Nan::New("findBoundariesAfter").ToLocalChecked(), Nan::New(find_boundaries_after), None); - Nan::SetTemplate(prototype_template, Nan::New("dump").ToLocalChecked(), Nan::New(dump), None); - - start_string.Reset(Nan::Persistent(Nan::New("start").ToLocalChecked())); - end_string.Reset(Nan::Persistent(Nan::New("end").ToLocalChecked())); - touch_string.Reset(Nan::Persistent(Nan::New("touch").ToLocalChecked())); - inside_string.Reset(Nan::Persistent(Nan::New("inside").ToLocalChecked())); - overlap_string.Reset(Nan::Persistent(Nan::New("overlap").ToLocalChecked())); - surround_string.Reset(Nan::Persistent(Nan::New("surround").ToLocalChecked())); - containing_start_string.Reset(Nan::Persistent(Nan::New("containingStart").ToLocalChecked())); - boundaries_string.Reset(Nan::Persistent(Nan::New("boundaries").ToLocalChecked())); - position_string.Reset(Nan::Persistent(Nan::New("position").ToLocalChecked())); - starting_string.Reset(Nan::Persistent(Nan::New("starting").ToLocalChecked())); - ending_string.Reset(Nan::Persistent(Nan::New("ending").ToLocalChecked())); - - marker_index_constructor_template.Reset(constructor_template); - Nan::Set(exports, Nan::New("MarkerIndex").ToLocalChecked(), Nan::GetFunction(constructor_template).ToLocalChecked()); +// using namespace v8; +// using std::unordered_map; +// +// static Nan::Persistent marker_index_constructor_template; +// static Nan::Persistent start_string; +// static Nan::Persistent end_string; +// static Nan::Persistent touch_string; +// static Nan::Persistent inside_string; +// static Nan::Persistent overlap_string; +// static Nan::Persistent surround_string; +// static Nan::Persistent containing_start_string; +// static Nan::Persistent boundaries_string; +// static Nan::Persistent position_string; +// static Nan::Persistent starting_string; +// static Nan::Persistent ending_string; +// +Napi::FunctionReference *MarkerIndexWrapper::constructor; + +void MarkerIndexWrapper::init(Napi::Env env, Napi::Object exports) { + Napi::Function func = DefineClass(env, "MarkerIndex", { + InstanceMethod<&MarkerIndexWrapper::splice>("splice"), + InstanceMethod<&MarkerIndexWrapper::has>("has"), + InstanceMethod<&MarkerIndexWrapper::insert>("insert"), + InstanceMethod<&MarkerIndexWrapper::compare>("compare"), + InstanceMethod<&MarkerIndexWrapper::get_start>("getStart"), + InstanceMethod<&MarkerIndexWrapper::get_end>("getEnd"), + InstanceMethod<&MarkerIndexWrapper::get_range>("getRange"), + InstanceMethod<&MarkerIndexWrapper::set_exclusive>("setExclusive"), + InstanceMethod<&MarkerIndexWrapper::find_starting_at>("findStartingAt"), + InstanceMethod<&MarkerIndexWrapper::find_starting_in>("findStartingIn"), + InstanceMethod<&MarkerIndexWrapper::find_ending_at>("findEndingAt"), + InstanceMethod<&MarkerIndexWrapper::find_ending_in>("findEndingIn"), + InstanceMethod<&MarkerIndexWrapper::remove>("remove"), + InstanceMethod<&MarkerIndexWrapper::dump>("dump"), + InstanceMethod<&MarkerIndexWrapper::find_intersecting>("findIntersecting"), + InstanceMethod<&MarkerIndexWrapper::find_containing>("findContaining"), + }); + + constructor = new Napi::FunctionReference(); + *constructor = Napi::Persistent(func); + exports.Set("MarkerIndex", func); } -MarkerIndex *MarkerIndexWrapper::from_js(Local value) { - auto js_marker_index = Local::Cast(value); - if (!Nan::New(marker_index_constructor_template)->HasInstance(js_marker_index)) { - return nullptr; - } - return &Nan::ObjectWrap::Unwrap(js_marker_index)->marker_index; -} - -void MarkerIndexWrapper::construct(const Nan::FunctionCallbackInfo &info) { - auto seed = Nan::To(info[0]); - MarkerIndexWrapper *marker_index = new MarkerIndexWrapper(seed.IsJust() ? seed.FromJust() : 0u); - marker_index->Wrap(info.This()); +#include +MarkerIndexWrapper::MarkerIndexWrapper(const Napi::CallbackInfo& info) + : Napi::ObjectWrap(info) { + // if(info[0].IsNumber()) { + // auto seed = info[0].ToNumber(); + // auto index = new MarkerIndex { seed.Uint32Value() }; + // this->marker_index = *index; + // } } -void MarkerIndexWrapper::generate_random_number(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - int random = wrapper->marker_index.generate_random_number(); - info.GetReturnValue().Set(Nan::New(random)); +Napi::Value MarkerIndexWrapper::splice(const Napi::CallbackInfo &info) { + auto env = info.Env(); + optional start = PointWrapper::point_from_js(info[0]); + optional old_extent = PointWrapper::point_from_js(info[1]); + optional new_extent = PointWrapper::point_from_js(info[2]); + if (start && old_extent && new_extent) { + MarkerIndex::SpliceResult result = marker_index.splice( + *start, *old_extent, *new_extent + ); + + auto invalidated = Napi::Object::New(env); + invalidated.Set("touch", marker_ids_set_to_js(env, result.touch)); + invalidated.Set("inside", marker_ids_set_to_js(env, result.inside)); + invalidated.Set("overlap", marker_ids_set_to_js(env, result.overlap)); + invalidated.Set("surround", marker_ids_set_to_js(env, result.surround)); + return invalidated; + } else { + return env.Undefined(); + } } -Local MarkerIndexWrapper::marker_ids_set_to_js(const MarkerIndex::MarkerIdSet &marker_ids) { - Isolate *isolate = v8::Isolate::GetCurrent(); - Local context = isolate->GetCurrentContext(); - Local js_set = v8::Set::New(isolate); - +// MarkerIndex *MarkerIndexWrapper::from_js(Local value) { +// auto js_marker_index = Local::Cast(value); +// if (!Nan::New(marker_index_constructor_template)->HasInstance(js_marker_index)) { +// return nullptr; +// } +// return &Nan::ObjectWrap::Unwrap(js_marker_index)->marker_index; +// } +// +// void MarkerIndexWrapper::construct(const Nan::FunctionCallbackInfo &info) { +// auto seed = Nan::To(info[0]); +// MarkerIndexWrapper *marker_index = new MarkerIndexWrapper(seed.IsJust() ? seed.FromJust() : 0u); +// marker_index->Wrap(info.This()); +// } +// +// void MarkerIndexWrapper::generate_random_number(const Nan::FunctionCallbackInfo &info) { +// MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); +// int random = wrapper->marker_index.generate_random_number(); +// info.GetReturnValue().Set(Nan::New(random)); +// } +// +Napi::Object MarkerIndexWrapper::marker_ids_set_to_js(Napi::Env env, const MarkerIndex::MarkerIdSet &marker_ids) { + auto js_set = env.RunScript("new Set()").ToObject(); + auto add_to_set = js_set.Get("add").As(); for (MarkerIndex::MarkerId id : marker_ids) { - // Not sure why Set::Add warns if we don't use its return value, but - // just doing it to avoid the warning. - js_set = js_set->Add(context, Nan::New(id)).ToLocalChecked(); + auto params = std::initializer_list { Napi::Number::New(env, id) }; + add_to_set.Call(js_set, params); } - return js_set; } - -Local MarkerIndexWrapper::marker_ids_vector_to_js(const std::vector &marker_ids) { - Local js_array = Nan::New(marker_ids.size()); - - Isolate *isolate = v8::Isolate::GetCurrent(); - Local context = isolate->GetCurrentContext(); - for (size_t i = 0; i < marker_ids.size(); i++) { - js_array->Set(context, i, Nan::New(marker_ids[i])); - } - return js_array; -} - -Local MarkerIndexWrapper::snapshot_to_js(const unordered_map &snapshot) { - Local result_object = Nan::New(); - Isolate *isolate = v8::Isolate::GetCurrent(); - Local context = isolate->GetCurrentContext(); - for (auto &pair : snapshot) { - Local range = Nan::New(); - range->Set(context, Nan::New(start_string), PointWrapper::from_point(pair.second.start)); - range->Set(context, Nan::New(end_string), PointWrapper::from_point(pair.second.end)); - result_object->Set(context, Nan::New(pair.first), range); - } - return result_object; -} - -optional MarkerIndexWrapper::marker_id_from_js(Local value) { - auto result = unsigned_from_js(value); - if (result) { - return *result; +// +// Local MarkerIndexWrapper::marker_ids_vector_to_js(const std::vector &marker_ids) { +// Local js_array = Nan::New(marker_ids.size()); +// +// Isolate *isolate = v8::Isolate::GetCurrent(); +// Local context = isolate->GetCurrentContext(); +// for (size_t i = 0; i < marker_ids.size(); i++) { +// js_array->Set(context, i, Nan::New(marker_ids[i])); +// } +// return js_array; +// } +// + +optional MarkerIndexWrapper::marker_id_from_js(Napi::Value value) { + if(!value.IsNumber() || value.ToNumber().DoubleValue() < 0) { + Napi::TypeError::New(value.Env(), "Expected an non-negative integer value").ThrowAsJavaScriptException(); + return optional(); } else { - return optional{}; - } -} - -optional MarkerIndexWrapper::unsigned_from_js(Local value) { - Nan::Maybe result = Nan::To(value); - if (!result.IsJust()) { - Nan::ThrowTypeError("Expected an non-negative integer value."); - return optional{}; + auto result = value.ToNumber(); + return optional(result.Uint32Value()); } - return result.FromJust(); } -optional MarkerIndexWrapper::bool_from_js(Local value) { - Nan::MaybeLocal maybe_boolean = Nan::To(value); - Local boolean; - if (!maybe_boolean.ToLocal(&boolean)) { - Nan::ThrowTypeError("Expected an boolean."); - return optional{}; - } - - return boolean->Value(); -} - -void MarkerIndexWrapper::insert(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - +Napi::Value MarkerIndexWrapper::insert(const Napi::CallbackInfo &info) { + auto env = info.Env(); optional id = marker_id_from_js(info[0]); optional start = PointWrapper::point_from_js(info[1]); optional end = PointWrapper::point_from_js(info[2]); if (id && start && end) { - wrapper->marker_index.insert(*id, *start, *end); + marker_index.insert(*id, *start, *end); } + return env.Undefined(); } -void MarkerIndexWrapper::set_exclusive(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - +Napi::Value MarkerIndexWrapper::set_exclusive(const Napi::CallbackInfo &info) { + auto env = info.Env(); optional id = marker_id_from_js(info[0]); - optional exclusive = bool_from_js(info[1]); - if (id && exclusive) { - wrapper->marker_index.set_exclusive(*id, *exclusive); + if (id && info[1].IsBoolean()) { + marker_index.set_exclusive(*id, info[1].ToBoolean().Value()); } + return env.Undefined(); } -void MarkerIndexWrapper::remove(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - +Napi::Value MarkerIndexWrapper::remove(const Napi::CallbackInfo &info) { + auto env = info.Env(); optional id = marker_id_from_js(info[0]); if (id) { - wrapper->marker_index.remove(*id); + marker_index.remove(*id); } + return env.Undefined(); } - -void MarkerIndexWrapper::has(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - - optional id = marker_id_from_js(info[0]); +// +Napi::Value MarkerIndexWrapper::has(const Napi::CallbackInfo &info) { + auto env = info.Env(); + auto id = marker_id_from_js(info[0]); if (id) { - bool result = wrapper->marker_index.has(*id); - info.GetReturnValue().Set(Nan::New(result)); - } -} - -void MarkerIndexWrapper::splice(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - - optional start = PointWrapper::point_from_js(info[0]); - optional old_extent = PointWrapper::point_from_js(info[1]); - optional new_extent = PointWrapper::point_from_js(info[2]); - if (start && old_extent && new_extent) { - MarkerIndex::SpliceResult result = wrapper->marker_index.splice(*start, *old_extent, *new_extent); - - Local invalidated = Nan::New(); - Nan::Set(invalidated, Nan::New(touch_string), marker_ids_set_to_js(result.touch)); - Nan::Set(invalidated, Nan::New(inside_string), marker_ids_set_to_js(result.inside)); - Nan::Set(invalidated, Nan::New(inside_string), marker_ids_set_to_js(result.inside)); - Nan::Set(invalidated, Nan::New(overlap_string), marker_ids_set_to_js(result.overlap)); - Nan::Set(invalidated, Nan::New(surround_string), marker_ids_set_to_js(result.surround)); - info.GetReturnValue().Set(invalidated); + bool result = marker_index.has(*id); + return Napi::Boolean::New(env, result); + } else { + return env.Undefined(); } } -void MarkerIndexWrapper::get_start(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - +Napi::Value MarkerIndexWrapper::get_start(const Napi::CallbackInfo &info) { + auto env = info.Env(); optional id = marker_id_from_js(info[0]); if (id) { - Point result = wrapper->marker_index.get_start(*id); - info.GetReturnValue().Set(PointWrapper::from_point(result)); + Range range = marker_index.get_range(*id); + return PointWrapper::from_point(env, range.start); + } else { + return env.Undefined(); } } -void MarkerIndexWrapper::get_end(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - +Napi::Value MarkerIndexWrapper::get_end(const Napi::CallbackInfo &info) { + auto env = info.Env(); optional id = marker_id_from_js(info[0]); if (id) { - Point result = wrapper->marker_index.get_end(*id); - info.GetReturnValue().Set(PointWrapper::from_point(result)); + Range range = marker_index.get_range(*id); + return PointWrapper::from_point(env, range.end); + } else { + return env.Undefined(); } } -void MarkerIndexWrapper::get_range(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - +Napi::Value MarkerIndexWrapper::get_range(const Napi::CallbackInfo &info) { + auto env = info.Env(); optional id = marker_id_from_js(info[0]); if (id) { - Range range = wrapper->marker_index.get_range(*id); - auto result = Nan::New(); - Nan::Set(result, Nan::New(start_string), PointWrapper::from_point(range.start)); - Nan::Set(result, Nan::New(end_string), PointWrapper::from_point(range.end)); - info.GetReturnValue().Set(result); + Range range = marker_index.get_range(*id); + auto result = Napi::Object::New(env); + result.Set("start", PointWrapper::from_point(env, range.start)); + result.Set("end", PointWrapper::from_point(env, range.end)); + return result; + } else { + return env.Undefined(); } } - -void MarkerIndexWrapper::compare(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); +// +Napi::Value MarkerIndexWrapper::compare(const Napi::CallbackInfo &info) { + auto env = info.Env(); optional id1 = marker_id_from_js(info[0]); optional id2 = marker_id_from_js(info[1]); if (id1 && id2) { - info.GetReturnValue().Set(wrapper->marker_index.compare(*id1, *id2)); + auto r = marker_index.compare(*id1, *id2); + return Napi::Number::New(env, r); + } else { + return env.Undefined(); } } -void MarkerIndexWrapper::find_intersecting(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - +Napi::Value MarkerIndexWrapper::find_intersecting(const Napi::CallbackInfo &info) { + auto env = info.Env(); optional start = PointWrapper::point_from_js(info[0]); optional end = PointWrapper::point_from_js(info[1]); if (start && end) { - MarkerIndex::MarkerIdSet result = wrapper->marker_index.find_intersecting(*start, *end); - info.GetReturnValue().Set(marker_ids_set_to_js(result)); + MarkerIndex::MarkerIdSet result = marker_index.find_intersecting(*start, *end); + return marker_ids_set_to_js(env, result); + } else { + return env.Undefined(); } } -void MarkerIndexWrapper::find_containing(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - +Napi::Value MarkerIndexWrapper::find_containing(const Napi::CallbackInfo &info) { + auto env = info.Env(); optional start = PointWrapper::point_from_js(info[0]); optional end = PointWrapper::point_from_js(info[1]); if (start && end) { - MarkerIndex::MarkerIdSet result = wrapper->marker_index.find_containing(*start, *end); - info.GetReturnValue().Set(marker_ids_set_to_js(result)); + MarkerIndex::MarkerIdSet result = marker_index.find_containing(*start, *end); + return marker_ids_set_to_js(env, result); + } else { + return env.Undefined(); } } +// +// void MarkerIndexWrapper::find_containing(const Nan::FunctionCallbackInfo &info) { +// MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); +// +// optional start = PointWrapper::point_from_js(info[0]); +// optional end = PointWrapper::point_from_js(info[1]); +// +// if (start && end) { +// MarkerIndex::MarkerIdSet result = wrapper->marker_index.find_containing(*start, *end); +// info.GetReturnValue().Set(marker_ids_set_to_js(result)); +// } +// } +// +// void MarkerIndexWrapper::find_contained_in(const Nan::FunctionCallbackInfo &info) { +// MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); +// +// optional start = PointWrapper::point_from_js(info[0]); +// optional end = PointWrapper::point_from_js(info[1]); +// +// if (start && end) { +// MarkerIndex::MarkerIdSet result = wrapper->marker_index.find_contained_in(*start, *end); +// info.GetReturnValue().Set(marker_ids_set_to_js(result)); +// } +// } +// +// void MarkerIndexWrapper::find_starting_in(const Nan::FunctionCallbackInfo &info) { +// MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); +// +// optional start = PointWrapper::point_from_js(info[0]); +// optional end = PointWrapper::point_from_js(info[1]); +// +// if (start && end) { +// MarkerIndex::MarkerIdSet result = wrapper->marker_index.find_starting_in(*start, *end); +// info.GetReturnValue().Set(marker_ids_set_to_js(result)); +// } +// } +// +// void MarkerIndexWrapper::find_starting_at(const Nan::FunctionCallbackInfo &info) { +// MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); +// +// optional position = PointWrapper::point_from_js(info[0]); +// +// if (position) { +// MarkerIndex::MarkerIdSet result = wrapper->marker_index.find_starting_at(*position); +// info.GetReturnValue().Set(marker_ids_set_to_js(result)); +// } +// } +// +// void MarkerIndexWrapper::find_ending_in(const Nan::FunctionCallbackInfo &info) { +// MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); +// +// optional start = PointWrapper::point_from_js(info[0]); +// optional end = PointWrapper::point_from_js(info[1]); +// +// if (start && end) { +// MarkerIndex::MarkerIdSet result = wrapper->marker_index.find_ending_in(*start, *end); +// info.GetReturnValue().Set(marker_ids_set_to_js(result)); +// } +// } +// + +Napi::Value MarkerIndexWrapper::find_ending_at(const Napi::CallbackInfo &info) { + auto env = info.Env(); + optional position = PointWrapper::point_from_js(info[0]); -void MarkerIndexWrapper::find_contained_in(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - - optional start = PointWrapper::point_from_js(info[0]); - optional end = PointWrapper::point_from_js(info[1]); - - if (start && end) { - MarkerIndex::MarkerIdSet result = wrapper->marker_index.find_contained_in(*start, *end); - info.GetReturnValue().Set(marker_ids_set_to_js(result)); + if (position) { + MarkerIndex::MarkerIdSet result = marker_index.find_ending_at(*position); + return marker_ids_set_to_js(env, result); + } else { + return env.Undefined(); } } -void MarkerIndexWrapper::find_starting_in(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - +Napi::Value MarkerIndexWrapper::find_ending_in(const Napi::CallbackInfo &info) { + auto env = info.Env(); optional start = PointWrapper::point_from_js(info[0]); optional end = PointWrapper::point_from_js(info[1]); if (start && end) { - MarkerIndex::MarkerIdSet result = wrapper->marker_index.find_starting_in(*start, *end); - info.GetReturnValue().Set(marker_ids_set_to_js(result)); + MarkerIndex::MarkerIdSet result = marker_index.find_ending_in(*start, *end); + return marker_ids_set_to_js(env, result); + } else { + return env.Undefined(); } } -void MarkerIndexWrapper::find_starting_at(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - +Napi::Value MarkerIndexWrapper::find_starting_at(const Napi::CallbackInfo &info) { + auto env = info.Env(); optional position = PointWrapper::point_from_js(info[0]); if (position) { - MarkerIndex::MarkerIdSet result = wrapper->marker_index.find_starting_at(*position); - info.GetReturnValue().Set(marker_ids_set_to_js(result)); + MarkerIndex::MarkerIdSet result = marker_index.find_starting_at(*position); + return marker_ids_set_to_js(env, result); + } else { + return env.Undefined(); } } -void MarkerIndexWrapper::find_ending_in(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - +Napi::Value MarkerIndexWrapper::find_starting_in(const Napi::CallbackInfo &info) { + auto env = info.Env(); optional start = PointWrapper::point_from_js(info[0]); optional end = PointWrapper::point_from_js(info[1]); if (start && end) { - MarkerIndex::MarkerIdSet result = wrapper->marker_index.find_ending_in(*start, *end); - info.GetReturnValue().Set(marker_ids_set_to_js(result)); - } -} - -void MarkerIndexWrapper::find_ending_at(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - - optional position = PointWrapper::point_from_js(info[0]); - - if (position) { - MarkerIndex::MarkerIdSet result = wrapper->marker_index.find_ending_at(*position); - info.GetReturnValue().Set(marker_ids_set_to_js(result)); + MarkerIndex::MarkerIdSet result = marker_index.find_starting_in(*start, *end); + return marker_ids_set_to_js(env, result); + } else { + return env.Undefined(); } } -void MarkerIndexWrapper::find_boundaries_after(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - - optional start = PointWrapper::point_from_js(info[0]); - optional max_count; - Local js_max_count; - if (Nan::To(info[1]).ToLocal(&js_max_count)) { - max_count = Nan::To(js_max_count).FromMaybe(0); +// void MarkerIndexWrapper::find_boundaries_after(const Nan::FunctionCallbackInfo &info) { +// MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); +// +// optional start = PointWrapper::point_from_js(info[0]); +// optional max_count; +// Local js_max_count; +// if (Nan::To(info[1]).ToLocal(&js_max_count)) { +// max_count = Nan::To(js_max_count).FromMaybe(0); +// } +// +// if (start && max_count) { +// MarkerIndex::BoundaryQueryResult result = wrapper->marker_index.find_boundaries_after(*start, *max_count); +// Local js_result = Nan::New(); +// Nan::Set(js_result, Nan::New(containing_start_string), marker_ids_vector_to_js(result.containing_start)); +// +// Local js_boundaries = Nan::New(result.boundaries.size()); +// for (size_t i = 0; i < result.boundaries.size(); i++) { +// MarkerIndex::Boundary boundary = result.boundaries[i]; +// Local js_boundary = Nan::New(); +// Nan::Set(js_boundary, Nan::New(position_string), PointWrapper::from_point(boundary.position)); +// Nan::Set(js_boundary, Nan::New(starting_string), marker_ids_set_to_js(boundary.starting)); +// Nan::Set(js_boundary, Nan::New(ending_string), marker_ids_set_to_js(boundary.ending)); +// Nan::Set(js_boundaries, i, js_boundary); +// } +// Nan::Set(js_result, Nan::New(boundaries_string), js_boundaries); +// +// info.GetReturnValue().Set(js_result); +// } +// } +// +Napi::Value MarkerIndexWrapper::dump(const Napi::CallbackInfo &info) { + auto env = info.Env(); + auto snapshot = marker_index.dump(); + auto result_object = Napi::Object::New(env); + for (auto pair : snapshot) { + auto range = Napi::Object::New(env); + range.Set("start", PointWrapper::from_point(env, pair.second.start)); + range.Set("end", PointWrapper::from_point(env, pair.second.end)); + result_object.Set(pair.first, range); } - - if (start && max_count) { - MarkerIndex::BoundaryQueryResult result = wrapper->marker_index.find_boundaries_after(*start, *max_count); - Local js_result = Nan::New(); - Nan::Set(js_result, Nan::New(containing_start_string), marker_ids_vector_to_js(result.containing_start)); - - Local js_boundaries = Nan::New(result.boundaries.size()); - for (size_t i = 0; i < result.boundaries.size(); i++) { - MarkerIndex::Boundary boundary = result.boundaries[i]; - Local js_boundary = Nan::New(); - Nan::Set(js_boundary, Nan::New(position_string), PointWrapper::from_point(boundary.position)); - Nan::Set(js_boundary, Nan::New(starting_string), marker_ids_set_to_js(boundary.starting)); - Nan::Set(js_boundary, Nan::New(ending_string), marker_ids_set_to_js(boundary.ending)); - Nan::Set(js_boundaries, i, js_boundary); - } - Nan::Set(js_result, Nan::New(boundaries_string), js_boundaries); - - info.GetReturnValue().Set(js_result); - } -} - -void MarkerIndexWrapper::dump(const Nan::FunctionCallbackInfo &info) { - MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - unordered_map snapshot = wrapper->marker_index.dump(); - info.GetReturnValue().Set(snapshot_to_js(snapshot)); + return result_object; } - -MarkerIndexWrapper::MarkerIndexWrapper(unsigned seed) : marker_index{seed} {} diff --git a/src/bindings/marker-index-wrapper.h b/src/bindings/marker-index-wrapper.h index 2f64cc54..bccd21a5 100644 --- a/src/bindings/marker-index-wrapper.h +++ b/src/bindings/marker-index-wrapper.h @@ -1,41 +1,41 @@ -#include "nan.h" +#include "napi.h" #include "marker-index.h" #include "optional.h" #include "range.h" -class MarkerIndexWrapper : public Nan::ObjectWrap { +class MarkerIndexWrapper : public Napi::ObjectWrap { public: - static void init(v8::Local exports); - static MarkerIndex *from_js(v8::Local); - + static void init(Napi::Env env, Napi::Object exports); + MarkerIndexWrapper(const Napi::CallbackInfo& info); +// static void init(v8::Local exports); + // static MarkerIndex *from_js(v8::Local); +// private: - static void construct(const Nan::FunctionCallbackInfo &info); - static void generate_random_number(const Nan::FunctionCallbackInfo &info); - static bool is_finite(v8::Local number); - static v8::Local marker_ids_set_to_js(const MarkerIndex::MarkerIdSet &marker_ids); - static v8::Local marker_ids_vector_to_js(const std::vector &marker_ids); - static v8::Local snapshot_to_js(const std::unordered_map &snapshot); - static optional marker_id_from_js(v8::Local value); - static optional unsigned_from_js(v8::Local value); - static optional bool_from_js(v8::Local value); - static void insert(const Nan::FunctionCallbackInfo &info); - static void set_exclusive(const Nan::FunctionCallbackInfo &info); - static void remove(const Nan::FunctionCallbackInfo &info); - static void has(const Nan::FunctionCallbackInfo &info); - static void splice(const Nan::FunctionCallbackInfo &info); - static void get_start(const Nan::FunctionCallbackInfo &info); - static void get_end(const Nan::FunctionCallbackInfo &info); - static void get_range(const Nan::FunctionCallbackInfo &info); - static void compare(const Nan::FunctionCallbackInfo &info); - static void find_intersecting(const Nan::FunctionCallbackInfo &info); - static void find_containing(const Nan::FunctionCallbackInfo &info); - static void find_contained_in(const Nan::FunctionCallbackInfo &info); - static void find_starting_in(const Nan::FunctionCallbackInfo &info); - static void find_starting_at(const Nan::FunctionCallbackInfo &info); - static void find_ending_in(const Nan::FunctionCallbackInfo &info); - static void find_ending_at(const Nan::FunctionCallbackInfo &info); - static void find_boundaries_after(const Nan::FunctionCallbackInfo &info); - static void dump(const Nan::FunctionCallbackInfo &info); - MarkerIndexWrapper(unsigned seed); + Napi::Value splice(const Napi::CallbackInfo &info); +// static void generate_random_number(const Nan::FunctionCallbackInfo &info); +// static bool is_finite(v8::Local number); + static Napi::Object marker_ids_set_to_js(Napi::Env env, const MarkerIndex::MarkerIdSet &marker_ids); + Napi::Value has(const Napi::CallbackInfo &info); + static optional marker_id_from_js(Napi::Value value); + Napi::Value insert(const Napi::CallbackInfo &info); + Napi::Value compare(const Napi::CallbackInfo &info); + Napi::Value get_start(const Napi::CallbackInfo &info); + Napi::Value get_end(const Napi::CallbackInfo &info); + Napi::Value get_range(const Napi::CallbackInfo &info); + Napi::Value set_exclusive(const Napi::CallbackInfo &info); + Napi::Value remove(const Napi::CallbackInfo &info); + Napi::Value find_ending_at(const Napi::CallbackInfo &info); + Napi::Value find_ending_in(const Napi::CallbackInfo &info); + Napi::Value find_starting_at(const Napi::CallbackInfo &info); + Napi::Value find_starting_in(const Napi::CallbackInfo &info); + Napi::Value dump(const Napi::CallbackInfo &info); + Napi::Value find_intersecting(const Napi::CallbackInfo &info); + Napi::Value find_containing(const Napi::CallbackInfo &info); +// static v8::Local marker_ids_vector_to_js(const std::vector &marker_ids); +// static v8::Local snapshot_to_js(const std::unordered_map &snapshot); +// static void find_contained_in(const Nan::FunctionCallbackInfo &info); +// static void find_boundaries_after(const Nan::FunctionCallbackInfo &info); +// MarkerIndexWrapper(unsigned seed); MarkerIndex marker_index; + static Napi::FunctionReference *constructor; }; diff --git a/src/bindings/patch-wrapper.cc b/src/bindings/patch-wrapper.cc index fc610aaf..01e6bf20 100644 --- a/src/bindings/patch-wrapper.cc +++ b/src/bindings/patch-wrapper.cc @@ -1,410 +1,385 @@ -#include "noop.h" +#include +// #include "noop.h" #include "patch-wrapper.h" -#include -#include -#include +// #include +// #include +// #include #include "point-wrapper.h" -#include "string-conversion.h" - -using namespace v8; -using std::move; -using std::vector; -using std::u16string; - -static Nan::Persistent new_text_string; -static Nan::Persistent old_text_string; -static Nan::Persistent change_wrapper_constructor; -static Nan::Persistent patch_wrapper_constructor_template; -static Nan::Persistent patch_wrapper_constructor; - -static const char *InvalidSpliceMessage = "Patch does not apply"; - -class ChangeWrapper : public Nan::ObjectWrap { +// #include "string-conversion.h" +// +// using namespace v8; +// using std::vector; +// using std::u16string; +// +// static Nan::Persistent new_text_string; +// static Nan::Persistent old_text_string; +// static Nan::Persistent change_wrapper_constructor; +// static Nan::Persistent patch_wrapper_constructor_template; +// static Nan::Persistent patch_wrapper_constructor; +// +// static const char *InvalidSpliceMessage = "Patch does not apply"; + +class ChangeWrapper : public Napi::ObjectWrap { public: - static void init() { - new_text_string.Reset(Nan::New("newText").ToLocalChecked()); - old_text_string.Reset(Nan::New("oldText").ToLocalChecked()); - static Nan::Persistent old_text_string; - - Local constructor_template = Nan::New(construct); - constructor_template->SetClassName(Nan::New("Change").ToLocalChecked()); - constructor_template->InstanceTemplate()->SetInternalFieldCount(1); - const auto &instance_template = constructor_template->InstanceTemplate(); - Nan::SetAccessor(instance_template, Nan::New("oldStart").ToLocalChecked(), get_old_start); - Nan::SetAccessor(instance_template, Nan::New("newStart").ToLocalChecked(), get_new_start); - Nan::SetAccessor(instance_template, Nan::New("oldEnd").ToLocalChecked(), get_old_end); - Nan::SetAccessor(instance_template, Nan::New("newEnd").ToLocalChecked(), get_new_end); - - const auto &prototype_template = constructor_template->PrototypeTemplate(); - Nan::SetTemplate(prototype_template, Nan::New("toString").ToLocalChecked(), Nan::New(to_string), None); - change_wrapper_constructor.Reset(Nan::GetFunction(constructor_template).ToLocalChecked()); + static void init(Napi::Env env) { + // new_text_string.Reset(Nan::New("newText").ToLocalChecked()); + // old_text_string.Reset(Nan::New("oldText").ToLocalChecked()); + // static Nan::Persistent old_text_string; + // + // Local constructor_template = Nan::New(construct); + // constructor_template->SetClassName(Nan::New("Change").ToLocalChecked()); + // constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + // const auto &instance_template = constructor_template->InstanceTemplate(); + // Nan::SetAccessor(instance_template, Nan::New("oldStart").ToLocalChecked(), get_old_start); + // Nan::SetAccessor(instance_template, Nan::New("newStart").ToLocalChecked(), get_new_start); + // Nan::SetAccessor(instance_template, Nan::New("oldEnd").ToLocalChecked(), get_old_end); + // Nan::SetAccessor(instance_template, Nan::New("newEnd").ToLocalChecked(), get_new_end); + // + // const auto &prototype_template = constructor_template->PrototypeTemplate(); + // Nan::SetTemplate(prototype_template, Nan::New("toString").ToLocalChecked(), Nan::New(to_string), None); + // change_wrapper_constructor.Reset(Nan::GetFunction(constructor_template).ToLocalChecked()); } - - static Local FromChange(Patch::Change change) { - Local result; - if (Nan::NewInstance(Nan::New(change_wrapper_constructor)).ToLocal(&result)) { - (new ChangeWrapper(change))->Wrap(result); - if (change.new_text) { - Nan::Set( - result, - Nan::New(new_text_string), - string_conversion::string_to_js(change.new_text->content) - ); - } - if (change.old_text) { - Nan::Set( - result, - Nan::New(old_text_string), - string_conversion::string_to_js(change.old_text->content) - ); - } - return result; - } else { - return Nan::Null(); +// + static Napi::Value FromChange(Napi::Env env, Patch::Change change) { + Napi::Object result = Napi::Object::New(env); + result.Set("oldStart", PointWrapper::from_point(env, change.old_start)); + result.Set("oldEnd", PointWrapper::from_point(env, change.old_end)); + result.Set("newStart", PointWrapper::from_point(env, change.new_start)); + result.Set("newEnd", PointWrapper::from_point(env, change.new_end)); + + if(change.new_text) { + result.Set("newText", Napi::String::From(env, change.new_text->content)); } + if(change.old_text) { + result.Set("oldText", Napi::String::From(env, change.old_text->content)); + } + return result; + // result.Set + // Local result; + // if (Nan::NewInstance(Nan::New(change_wrapper_constructor)).ToLocal(&result)) { + // (new ChangeWrapper(change))->Wrap(result); + // if (change.new_text) { + // Nan::Set( + // result, + // Nan::New(new_text_string), + // string_conversion::string_to_js(change.new_text->content) + // ); + // } + // if (change.old_text) { + // Nan::Set( + // result, + // Nan::New(old_text_string), + // string_conversion::string_to_js(change.old_text->content) + // ); + // } + // return result; + // } else { + // return Nan::Null(); + // } } - - private: - ChangeWrapper(Patch::Change change) : change(change) {} - - static void construct(const Nan::FunctionCallbackInfo &info) {} - - static void get_old_start(v8::Local property, const Nan::PropertyCallbackInfo &info) { - Patch::Change &change = Nan::ObjectWrap::Unwrap(info.This())->change; - info.GetReturnValue().Set(PointWrapper::from_point(change.old_start)); - } - - static void get_new_start(v8::Local property, const Nan::PropertyCallbackInfo &info) { - Patch::Change &change = Nan::ObjectWrap::Unwrap(info.This())->change; - info.GetReturnValue().Set(PointWrapper::from_point(change.new_start)); - } - - static void get_old_end(v8::Local property, const Nan::PropertyCallbackInfo &info) { - Patch::Change &change = Nan::ObjectWrap::Unwrap(info.This())->change; - info.GetReturnValue().Set(PointWrapper::from_point(change.old_end)); - } - - static void get_new_end(v8::Local property, const Nan::PropertyCallbackInfo &info) { - Patch::Change &change = Nan::ObjectWrap::Unwrap(info.This())->change; - info.GetReturnValue().Set(PointWrapper::from_point(change.new_end)); - } - - static void get_preceding_old_text_length(v8::Local property, const Nan::PropertyCallbackInfo &info) { - Patch::Change &change = Nan::ObjectWrap::Unwrap(info.This())->change; - info.GetReturnValue().Set(Nan::New(change.preceding_old_text_size)); - } - - static void get_preceding_new_text_length(v8::Local property, const Nan::PropertyCallbackInfo &info) { - Patch::Change &change = Nan::ObjectWrap::Unwrap(info.This())->change; - info.GetReturnValue().Set(Nan::New(change.preceding_new_text_size)); - } - - static void to_string(const Nan::FunctionCallbackInfo &info) { - Patch::Change &change = Nan::ObjectWrap::Unwrap(info.This())->change; - std::stringstream result; - result << change; - info.GetReturnValue().Set(Nan::New(result.str()).ToLocalChecked()); - } - +// +// private: +// ChangeWrapper(Patch::Change change) : change(change) {} +// +// static void construct(const Nan::FunctionCallbackInfo &info) {} +// +// static void get_old_start(v8::Local property, const Nan::PropertyCallbackInfo &info) { +// Patch::Change &change = Nan::ObjectWrap::Unwrap(info.This())->change; +// info.GetReturnValue().Set(PointWrapper::from_point(change.old_start)); +// } +// +// static void get_new_start(v8::Local property, const Nan::PropertyCallbackInfo &info) { +// Patch::Change &change = Nan::ObjectWrap::Unwrap(info.This())->change; +// info.GetReturnValue().Set(PointWrapper::from_point(change.new_start)); +// } +// +// static void get_old_end(v8::Local property, const Nan::PropertyCallbackInfo &info) { +// Patch::Change &change = Nan::ObjectWrap::Unwrap(info.This())->change; +// info.GetReturnValue().Set(PointWrapper::from_point(change.old_end)); +// } +// +// static void get_new_end(v8::Local property, const Nan::PropertyCallbackInfo &info) { +// Patch::Change &change = Nan::ObjectWrap::Unwrap(info.This())->change; +// info.GetReturnValue().Set(PointWrapper::from_point(change.new_end)); +// } +// +// static void get_preceding_old_text_length(v8::Local property, const Nan::PropertyCallbackInfo &info) { +// Patch::Change &change = Nan::ObjectWrap::Unwrap(info.This())->change; +// info.GetReturnValue().Set(Nan::New(change.preceding_old_text_size)); +// } +// +// static void get_preceding_new_text_length(v8::Local property, const Nan::PropertyCallbackInfo &info) { +// Patch::Change &change = Nan::ObjectWrap::Unwrap(info.This())->change; +// info.GetReturnValue().Set(Nan::New(change.preceding_new_text_size)); +// } +// +// static void to_string(const Nan::FunctionCallbackInfo &info) { +// Patch::Change &change = Nan::ObjectWrap::Unwrap(info.This())->change; +// std::stringstream result; +// result << change; +// info.GetReturnValue().Set(Nan::New(result.str()).ToLocalChecked()); +// } +// Patch::Change change; }; -void PatchWrapper::init(Local exports) { - ChangeWrapper::init(); - - Local constructor_template_local = Nan::New(construct); - constructor_template_local->SetClassName(Nan::New("Patch").ToLocalChecked()); - Nan::SetTemplate(constructor_template_local, Nan::New("deserialize").ToLocalChecked(), Nan::New(deserialize), None); - Nan::SetTemplate(constructor_template_local, Nan::New("compose").ToLocalChecked(), Nan::New(compose), None); - constructor_template_local->InstanceTemplate()->SetInternalFieldCount(1); - const auto &prototype_template = constructor_template_local->PrototypeTemplate(); - Nan::SetTemplate(prototype_template, Nan::New("delete").ToLocalChecked(), Nan::New(noop), None); - Nan::SetTemplate(prototype_template, Nan::New("splice").ToLocalChecked(), Nan::New(splice), None); - Nan::SetTemplate(prototype_template, Nan::New("spliceOld").ToLocalChecked(), Nan::New(splice_old), None); - Nan::SetTemplate(prototype_template, Nan::New("copy").ToLocalChecked(), Nan::New(copy), None); - Nan::SetTemplate(prototype_template, Nan::New("invert").ToLocalChecked(), Nan::New(invert), None); - Nan::SetTemplate(prototype_template, Nan::New("getChanges").ToLocalChecked(), Nan::New(get_changes), None); - Nan::SetTemplate(prototype_template, Nan::New("getChangesInOldRange").ToLocalChecked(), - Nan::New(get_changes_in_old_range), None); - Nan::SetTemplate(prototype_template, Nan::New("getChangesInNewRange").ToLocalChecked(), - Nan::New(get_changes_in_new_range), None); - Nan::SetTemplate(prototype_template, Nan::New("changeForOldPosition").ToLocalChecked(), - Nan::New(change_for_old_position), None); - Nan::SetTemplate(prototype_template, Nan::New("changeForNewPosition").ToLocalChecked(), - Nan::New(change_for_new_position), None); - Nan::SetTemplate(prototype_template, Nan::New("serialize").ToLocalChecked(), Nan::New(serialize), None); - Nan::SetTemplate(prototype_template, Nan::New("getDotGraph").ToLocalChecked(), Nan::New(get_dot_graph), None); - Nan::SetTemplate(prototype_template, Nan::New("getJSON").ToLocalChecked(), Nan::New(get_json), None); - Nan::SetTemplate(prototype_template, Nan::New("rebalance").ToLocalChecked(), Nan::New(rebalance), None); - Nan::SetTemplate(prototype_template, Nan::New("getChangeCount").ToLocalChecked(), Nan::New(get_change_count), None); - Nan::SetTemplate(prototype_template, Nan::New("getBounds").ToLocalChecked(), Nan::New(get_bounds), None); - patch_wrapper_constructor_template.Reset(constructor_template_local); - patch_wrapper_constructor.Reset(Nan::GetFunction(constructor_template_local).ToLocalChecked()); - Nan::Set(exports, Nan::New("Patch").ToLocalChecked(), Nan::New(patch_wrapper_constructor)); +Napi::FunctionReference *PatchWrapper::constructor; +void PatchWrapper::init(Napi::Env env, Napi::Object exports) { + ChangeWrapper::init(env); + + auto func = DefineClass(env, "Patch", { + StaticMethod<&PatchWrapper::deserialize>("deserialize"), + InstanceMethod<&PatchWrapper::serialize>("serialize"), + InstanceMethod<&PatchWrapper::splice>("splice"), + InstanceMethod<&PatchWrapper::splice_old>("spliceOld"), + InstanceMethod<&PatchWrapper::change_for_old_position>("changeForOldPosition"), + InstanceMethod<&PatchWrapper::change_for_new_position>("changeForNewPosition"), + InstanceMethod<&PatchWrapper::get_changes>("getChanges"), + InstanceMethod<&PatchWrapper::get_change_count>("getChangeCount"), + InstanceMethod<&PatchWrapper::get_changes_in_old_range>("getChangesInOldRange"), + InstanceMethod<&PatchWrapper::get_changes_in_new_range>("getChangesInNewRange"), + InstanceMethod<&PatchWrapper::invert>("invert"), + InstanceMethod<&PatchWrapper::copy>("copy"), + InstanceMethod<&PatchWrapper::rebalance>("rebalance"), + InstanceMethod<&PatchWrapper::get_bounds>("getBounds"), + StaticMethod<&PatchWrapper::compose>("compose") + // InstanceAccessor<&RangeWrapper::get_start>("start"), + // InstanceAccessor<&RangeWrapper::get_end>("end") + }); + constructor = new Napi::FunctionReference(); + *constructor = Napi::Persistent(func); + exports.Set("Patch", func); } -PatchWrapper::PatchWrapper(Patch &&patch) : patch{std::move(patch)} {} - -Local PatchWrapper::from_patch(Patch &&patch) { - Local result; - if (Nan::NewInstance(Nan::New(patch_wrapper_constructor)).ToLocal(&result)) { - (new PatchWrapper(move(patch)))->Wrap(result); - return result; - } else { - return Nan::Null(); - } -} - -void PatchWrapper::construct(const Nan::FunctionCallbackInfo &info) { - bool merges_adjacent_changes = true; - Local options; - - if (info.Length() > 0 && Nan::To(info[0]).ToLocal(&options)) { - Local js_merge_adjacent_changes; - if (Nan::Get(options, Nan::New("mergeAdjacentChanges").ToLocalChecked()).ToLocal(&js_merge_adjacent_changes)) { - merges_adjacent_changes = Nan::To(js_merge_adjacent_changes).FromMaybe(false); +PatchWrapper::PatchWrapper(const Napi::CallbackInfo &info) : Napi::ObjectWrap(info) { + if(info[0].IsExternal()) { + auto patch = info[0].As>(); + this->patch = std::move(*patch.Data()); + } else if(info[0].IsObject()) { + auto param = info[0].ToObject(); + if(param.Has("mergeAdjacentChanges")) { + bool merge_adjacent = param.Get("mergeAdjacentChanges").ToBoolean(); + this->patch = Patch{ merge_adjacent }; } } - PatchWrapper *patch = new PatchWrapper(Patch{merges_adjacent_changes}); - patch->Wrap(info.This()); } -void PatchWrapper::splice(const Nan::FunctionCallbackInfo &info) { - Patch &patch = Nan::ObjectWrap::Unwrap(info.This())->patch; - - optional start = PointWrapper::point_from_js(info[0]); - optional deletion_extent = PointWrapper::point_from_js(info[1]); - optional insertion_extent = PointWrapper::point_from_js(info[2]); +Napi::Value PatchWrapper::splice(const Napi::CallbackInfo &info) { + auto start = PointWrapper::point_from_js(info[0]); + auto deletion_extent = PointWrapper::point_from_js(info[1]); + auto insertion_extent = PointWrapper::point_from_js(info[2]); + auto env = info.Env(); if (start && deletion_extent && insertion_extent) { optional deleted_text; optional inserted_text; - if (info.Length() >= 4) { - auto deleted_string = string_conversion::string_from_js(info[3]); - if (!deleted_string) return; - deleted_text = Text{move(*deleted_string)}; + if(info[3].IsString()) { + deleted_text = optional(Text{info[3].ToString().Utf16Value()}); + } else { + return env.Undefined(); + } } if (info.Length() >= 5) { - auto inserted_string = string_conversion::string_from_js(info[4]); - if (!inserted_string) return; - inserted_text = Text{move(*inserted_string)}; + if(info[4].IsString()) { + inserted_text = optional(Text{info[4].ToString().Utf16Value()}); + } else { + return env.Undefined(); + } } - if (!patch.splice( + if (!this->patch.splice( *start, *deletion_extent, *insertion_extent, - move(deleted_text), - move(inserted_text) + std::move(deleted_text), + std::move(inserted_text) )) { - Nan::ThrowError(InvalidSpliceMessage); + Napi::Error::New(env, "Patch does not apply").ThrowAsJavaScriptException(); } } + return info.Env().Undefined(); } -void PatchWrapper::splice_old(const Nan::FunctionCallbackInfo &info) { - Patch &patch = Nan::ObjectWrap::Unwrap(info.This())->patch; - - optional start = PointWrapper::point_from_js(info[0]); - optional deletion_extent = PointWrapper::point_from_js(info[1]); - optional insertion_extent = PointWrapper::point_from_js(info[2]); +Napi::Value PatchWrapper::splice_old(const Napi::CallbackInfo &info) { + auto start = PointWrapper::point_from_js(info[0]); + auto deletion_extent = PointWrapper::point_from_js(info[1]); + auto insertion_extent = PointWrapper::point_from_js(info[2]); + auto env = info.Env(); if (start && deletion_extent && insertion_extent) { patch.splice_old(*start, *deletion_extent, *insertion_extent); } + return env.Undefined(); } -void PatchWrapper::copy(const Nan::FunctionCallbackInfo &info) { - Local result; - if (Nan::NewInstance(Nan::New(patch_wrapper_constructor)).ToLocal(&result)) { - Patch &patch = Nan::ObjectWrap::Unwrap(info.This())->patch; - auto wrapper = new PatchWrapper{patch.copy()}; - wrapper->Wrap(result); - info.GetReturnValue().Set(result); - } +Napi::Value PatchWrapper::copy(const Napi::CallbackInfo &info) { + auto copied = patch.copy(); + auto wrapped = Napi::External::New(info.Env(), &copied); + auto result = PatchWrapper::constructor->New({ wrapped }); + return result; } -void PatchWrapper::invert(const Nan::FunctionCallbackInfo &info) { - Local result; - if (Nan::NewInstance(Nan::New(patch_wrapper_constructor)).ToLocal(&result)) { - Patch &patch = Nan::ObjectWrap::Unwrap(info.This())->patch; - auto wrapper = new PatchWrapper{patch.invert()}; - wrapper->Wrap(result); - info.GetReturnValue().Set(result); - } +Napi::Value PatchWrapper::invert(const Napi::CallbackInfo &info) { + auto inverted = patch.invert(); + auto wrapped = Napi::External::New(info.Env(), &inverted); + auto result = PatchWrapper::constructor->New({ wrapped }); + return result; } -void PatchWrapper::get_changes(const Nan::FunctionCallbackInfo &info) { - Patch &patch = Nan::ObjectWrap::Unwrap(info.This())->patch; - - Local js_result = Nan::New(); +Napi::Value PatchWrapper::get_changes(const Napi::CallbackInfo &info) { + auto env = info.Env(); + auto t = Napi::ObjectWrap::Unwrap(info.This().ToObject()); + auto &patch = t->patch; + auto js_result = Napi::Array::New(env); size_t i = 0; for (auto change : patch.get_changes()) { - Nan::Set(js_result, i++, ChangeWrapper::FromChange(change)); + js_result.Set(i++, ChangeWrapper::FromChange(env, change)); } - - info.GetReturnValue().Set(js_result); + return js_result; } -void PatchWrapper::get_changes_in_old_range(const Nan::FunctionCallbackInfo &info) { - Patch &patch = Nan::ObjectWrap::Unwrap(info.This())->patch; - - optional start = PointWrapper::point_from_js(info[0]); - optional end = PointWrapper::point_from_js(info[1]); - +Napi::Value PatchWrapper::get_changes_in_old_range(const Napi::CallbackInfo &info) { + auto env = info.Env(); + auto start = PointWrapper::point_from_js(info[0]); + auto end = PointWrapper::point_from_js(info[1]); if (start && end) { - Local js_result = Nan::New(); - + auto changes = patch.grab_changes_in_old_range(*start, *start); + auto js_result = Napi::Array::New(env, changes.size()); size_t i = 0; - for (auto change : patch.grab_changes_in_old_range(*start, *end)) { - Nan::Set(js_result, i++, ChangeWrapper::FromChange(change)); + for (auto change : changes) { + js_result.Set(i++, ChangeWrapper::FromChange(env, change)); } - - info.GetReturnValue().Set(js_result); + return js_result; + } else { + return env.Undefined(); } } -void PatchWrapper::get_changes_in_new_range(const Nan::FunctionCallbackInfo &info) { - Patch &patch = Nan::ObjectWrap::Unwrap(info.This())->patch; - - optional start = PointWrapper::point_from_js(info[0]); - optional end = PointWrapper::point_from_js(info[1]); - +Napi::Value PatchWrapper::get_changes_in_new_range(const Napi::CallbackInfo &info) { + auto env = info.Env(); + auto start = PointWrapper::point_from_js(info[0]); + auto end = PointWrapper::point_from_js(info[1]); if (start && end) { - Local js_result = Nan::New(); - + auto changes = patch.grab_changes_in_new_range(*start, *start); + auto js_result = Napi::Array::New(env, changes.size()); size_t i = 0; - for (auto change : patch.grab_changes_in_new_range(*start, *end)) { - Nan::Set(js_result, i++, ChangeWrapper::FromChange(change)); + for (auto change : changes) { + js_result.Set(i++, ChangeWrapper::FromChange(env, change)); } - - info.GetReturnValue().Set(js_result); + return js_result; + } else { + return env.Undefined(); } } -void PatchWrapper::change_for_old_position(const Nan::FunctionCallbackInfo &info) { - Patch &patch = Nan::ObjectWrap::Unwrap(info.This())->patch; - optional start = PointWrapper::point_from_js(info[0]); +Napi::Value PatchWrapper::change_for_old_position(const Napi::CallbackInfo &info) { + auto start = PointWrapper::point_from_js(info[0]); if (start) { auto change = patch.grab_change_starting_before_old_position(*start); if (change) { - info.GetReturnValue().Set(ChangeWrapper::FromChange(*change)); - } else { - info.GetReturnValue().Set(Nan::Undefined()); + return ChangeWrapper::FromChange(info.Env(), *change); } } + return info.Env().Undefined(); } -void PatchWrapper::change_for_new_position(const Nan::FunctionCallbackInfo &info) { - Patch &patch = Nan::ObjectWrap::Unwrap(info.This())->patch; - optional start = PointWrapper::point_from_js(info[0]); +Napi::Value PatchWrapper::change_for_new_position(const Napi::CallbackInfo &info) { + auto start = PointWrapper::point_from_js(info[0]); if (start) { auto change = patch.grab_change_starting_before_new_position(*start); if (change) { - info.GetReturnValue().Set(ChangeWrapper::FromChange(*change)); - } else { - info.GetReturnValue().Set(Nan::Undefined()); + return ChangeWrapper::FromChange(info.Env(), *change); } } + return info.Env().Undefined(); } -void PatchWrapper::serialize(const Nan::FunctionCallbackInfo &info) { - Patch &patch = Nan::ObjectWrap::Unwrap(info.This())->patch; - - static vector output; +Napi::Value PatchWrapper::serialize(const Napi::CallbackInfo &info) { + static std::vector output; output.clear(); Serializer serializer(output); patch.serialize(serializer); - Local result; - auto maybe_result = - Nan::CopyBuffer(reinterpret_cast(output.data()), output.size()); - if (maybe_result.ToLocal(&result)) { - info.GetReturnValue().Set(result); - } + auto result = Napi::Buffer::Copy(info.Env(), output.data(), output.size()); + return result; } -void PatchWrapper::deserialize(const Nan::FunctionCallbackInfo &info) { - Local result; - if (Nan::NewInstance(Nan::New(patch_wrapper_constructor)).ToLocal(&result)) { - if (info[0]->IsUint8Array()) { - auto *data = node::Buffer::Data(info[0]); - static vector input; - input.assign(data, data + node::Buffer::Length(info[0])); - Deserializer deserializer(input); - PatchWrapper *wrapper = new PatchWrapper(Patch{deserializer}); - wrapper->Wrap(result); - info.GetReturnValue().Set(result); - } +Napi::Value PatchWrapper::deserialize(const Napi::CallbackInfo &info) { + if(info[0].IsBuffer()) { + auto buffer = info[0].As>(); + auto *data = buffer.Data(); + static std::vector input; + input.assign(data, data + buffer.Length()); + Deserializer deserializer(input); + auto new_patch = Patch{deserializer}; + auto wrapped = Napi::External::New(info.Env(), &new_patch); + return PatchWrapper::constructor->New({ wrapped }); + } else { + return info.Env().Undefined(); } } -void PatchWrapper::compose(const Nan::FunctionCallbackInfo &info) { - Local result; - if (Nan::NewInstance(Nan::New(patch_wrapper_constructor)).ToLocal(&result)) { - Local js_patches = Local::Cast(info[0]); - if (!js_patches->IsArray()) { - Nan::ThrowTypeError("Compose requires an array of patches"); - return; +Napi::Value PatchWrapper::compose(const Napi::CallbackInfo &info) { + auto env = info.Env(); + if(!info[0].IsArray()) { + Napi::Error::New(env, "Compose requires an array of patches").ThrowAsJavaScriptException(); + return env.Undefined(); + } + Napi::Array js_patches = info[0].As(); + + + auto values = std::initializer_list { }; + auto return_value = PatchWrapper::constructor->New(values); + auto combination = &PatchWrapper::Unwrap(return_value)->patch; + bool left_to_right = true; + for (uint32_t i = 0, n = js_patches.Length(); i < n; i++) { + Patch patch; + auto obj = js_patches.Get(i).ToObject(); + if(!obj.Has("getChangeCount")) { + // } catch (Napi::Error _) { + Napi::Error::New(env, "Patch.compose must be called with an array of patches").ThrowAsJavaScriptException(); + return env.Undefined(); } + patch = std::move(PatchWrapper::Unwrap(obj)->patch); - Patch combination; - bool left_to_right = true; - for (uint32_t i = 0, n = js_patches->Length(); i < n; i++) { - if (!Nan::Get(js_patches, i).ToLocalChecked()->IsObject()) { - Nan::ThrowTypeError("Patch.compose must be called with an array of patches"); - return; - } - - Local js_patch = Local::Cast(Nan::Get(js_patches, i).ToLocalChecked()); - if (!Nan::New(patch_wrapper_constructor_template)->HasInstance(js_patch)) { - Nan::ThrowTypeError("Patch.compose must be called with an array of patches"); - return; - } - - Patch &patch = Nan::ObjectWrap::Unwrap(js_patch)->patch; - if (!combination.combine(patch, left_to_right)) { - Nan::ThrowTypeError(InvalidSpliceMessage); - return; - } - left_to_right = !left_to_right; + if (!combination->combine(patch, left_to_right)) { + Napi::Error::New(env, "Patch does not apply").ThrowAsJavaScriptException(); + return env.Undefined(); } - - (new PatchWrapper{move(combination)})->Wrap(result); - info.GetReturnValue().Set(result); + left_to_right = !left_to_right; } -} -void PatchWrapper::get_dot_graph(const Nan::FunctionCallbackInfo &info) { - Patch &patch = Nan::ObjectWrap::Unwrap(info.This())->patch; - std::string graph = patch.get_dot_graph(); - info.GetReturnValue().Set(Nan::New(graph).ToLocalChecked()); + return return_value; } - -void PatchWrapper::get_json(const Nan::FunctionCallbackInfo &info) { - Patch &patch = Nan::ObjectWrap::Unwrap(info.This())->patch; - std::string graph = patch.get_json(); - info.GetReturnValue().Set(Nan::New(graph).ToLocalChecked()); -} - -void PatchWrapper::get_change_count(const Nan::FunctionCallbackInfo &info) { - Patch &patch = Nan::ObjectWrap::Unwrap(info.This())->patch; - uint32_t change_count = patch.get_change_count(); - info.GetReturnValue().Set(Nan::New(change_count)); +// +// void PatchWrapper::get_dot_graph(const Nan::FunctionCallbackInfo &info) { +// Patch &patch = Nan::ObjectWrap::Unwrap(info.This())->patch; +// std::string graph = patch.get_dot_graph(); +// info.GetReturnValue().Set(Nan::New(graph).ToLocalChecked()); +// } +// +// void PatchWrapper::get_json(const Nan::FunctionCallbackInfo &info) { +// Patch &patch = Nan::ObjectWrap::Unwrap(info.This())->patch; +// std::string graph = patch.get_json(); +// info.GetReturnValue().Set(Nan::New(graph).ToLocalChecked()); +// } +// +Napi::Value PatchWrapper::get_change_count(const Napi::CallbackInfo &info) { + return Napi::Value::From(info.Env(), this->patch.get_change_count()); } - -void PatchWrapper::get_bounds(const Nan::FunctionCallbackInfo &info) { - Patch &patch = Nan::ObjectWrap::Unwrap(info.This())->patch; +// +Napi::Value PatchWrapper::get_bounds(const Napi::CallbackInfo &info) { auto bounds = patch.get_bounds(); if (bounds) { - info.GetReturnValue().Set(ChangeWrapper::FromChange(*bounds)); + return ChangeWrapper::FromChange(info.Env(), *bounds); } + return info.Env().Undefined(); } -void PatchWrapper::rebalance(const Nan::FunctionCallbackInfo &info) { - Patch &patch = Nan::ObjectWrap::Unwrap(info.This())->patch; +Napi::Value PatchWrapper::rebalance(const Napi::CallbackInfo &info) { patch.rebalance(); + return info.Env().Undefined(); } diff --git a/src/bindings/patch-wrapper.h b/src/bindings/patch-wrapper.h index 97fc6133..1c82da0b 100644 --- a/src/bindings/patch-wrapper.h +++ b/src/bindings/patch-wrapper.h @@ -1,31 +1,34 @@ -#include +#include #include "patch.h" -class PatchWrapper : public Nan::ObjectWrap { +class PatchWrapper : public Napi::ObjectWrap { public: - static void init(v8::Local exports); - static v8::Local from_patch(Patch &&); + static void init(Napi::Env env, Napi::Object exports); + // static v8::Local from_patch(Patch &&); + PatchWrapper(const Napi::CallbackInfo &info); private: - PatchWrapper(Patch &&patch); - static void construct(const Nan::FunctionCallbackInfo &info); - static void splice(const Nan::FunctionCallbackInfo &info); - static void splice_old(const Nan::FunctionCallbackInfo &info); - static void copy(const Nan::FunctionCallbackInfo &info); - static void invert(const Nan::FunctionCallbackInfo &info); - static void get_changes(const Nan::FunctionCallbackInfo &info); - static void get_changes_in_old_range(const Nan::FunctionCallbackInfo &info); - static void get_changes_in_new_range(const Nan::FunctionCallbackInfo &info); - static void change_for_old_position(const Nan::FunctionCallbackInfo &info); - static void change_for_new_position(const Nan::FunctionCallbackInfo &info); - static void serialize(const Nan::FunctionCallbackInfo &info); - static void deserialize(const Nan::FunctionCallbackInfo &info); - static void compose(const Nan::FunctionCallbackInfo &info); - static void get_dot_graph(const Nan::FunctionCallbackInfo &info); - static void get_json(const Nan::FunctionCallbackInfo &info); - static void get_change_count(const Nan::FunctionCallbackInfo &info); - static void get_bounds(const Nan::FunctionCallbackInfo &info); - static void rebalance(const Nan::FunctionCallbackInfo &info); + static Napi::FunctionReference *constructor; + // static void construct(const Nan::FunctionCallbackInfo &info); + Napi::Value splice(const Napi::CallbackInfo &info); + Napi::Value splice_old(const Napi::CallbackInfo &info); + // static void copy(const Nan::FunctionCallbackInfo &info); + Napi::Value copy(const Napi::CallbackInfo &info); + Napi::Value invert(const Napi::CallbackInfo &info); + Napi::Value get_changes(const Napi::CallbackInfo &info); + Napi::Value get_changes_in_old_range(const Napi::CallbackInfo &info); + Napi::Value get_changes_in_new_range(const Napi::CallbackInfo &info); + Napi::Value change_for_old_position(const Napi::CallbackInfo &info); + Napi::Value change_for_new_position(const Napi::CallbackInfo &info); + // static void change_for_new_position(const Nan::FunctionCallbackInfo &info); + static Napi::Value deserialize(const Napi::CallbackInfo &info); + Napi::Value serialize(const Napi::CallbackInfo &info); + static Napi::Value compose(const Napi::CallbackInfo &info); + // static void get_dot_graph(const Nan::FunctionCallbackInfo &info); + // static void get_json(const Nan::FunctionCallbackInfo &info); + Napi::Value get_change_count(const Napi::CallbackInfo &info); + Napi::Value get_bounds(const Napi::CallbackInfo &info); + Napi::Value rebalance(const Napi::CallbackInfo &info); Patch patch; }; diff --git a/src/bindings/point-wrapper.cc b/src/bindings/point-wrapper.cc index 7bd159f7..e5a902ec 100644 --- a/src/bindings/point-wrapper.cc +++ b/src/bindings/point-wrapper.cc @@ -1,81 +1,81 @@ #include "point-wrapper.h" -#include -#include "nan.h" +#include "napi.h" +#include +#include -using namespace v8; - -static Nan::Persistent row_string; -static Nan::Persistent column_string; -static Nan::Persistent constructor; - -static uint32_t number_from_js(Local js_number) { - double number = Nan::To(js_number).FromMaybe(0); - if (number > 0 && !std::isfinite(number)) { - return UINT32_MAX; - } else { - return std::max(0.0, number); +// #include +auto Inf = std::numeric_limits::infinity(); +optional PointWrapper::point_from_js(Napi::Value value) { + Napi::Env env = value.Env(); + if (!value.IsObject()) { + Napi::TypeError::New(env, "Expected an object with 'row' and 'column' properties.").ThrowAsJavaScriptException(); + return optional(); } -} + Napi::Object object = value.ToObject(); -optional PointWrapper::point_from_js(Local value) { - Nan::MaybeLocal maybe_object = Nan::To(value); - Local object; - if (!maybe_object.ToLocal(&object)) { - Nan::ThrowTypeError("Expected an object with 'row' and 'column' properties."); - return optional{}; + auto js_row = object.Get("row"); + auto js_column = object.Get("column");; + if (!js_row.IsNumber() || !js_column.IsNumber()) { + Napi::TypeError::New(env, "Expected an object with 'row' and 'column' properties.").ThrowAsJavaScriptException(); + return optional(); } - Nan::MaybeLocal maybe_row = Nan::To(Nan::Get(object, Nan::New(row_string)).ToLocalChecked()); - Local js_row; - if (!maybe_row.ToLocal(&js_row)) { - Nan::ThrowTypeError("Expected an object with 'row' and 'column' properties."); - return optional{}; - } + auto row = js_row.ToNumber().DoubleValue(); + if(row == Inf) row = UINT_MAX; + auto col = js_column.ToNumber().DoubleValue(); + if(col == Inf) col = UINT_MAX; + return Point(row, col); +} - Nan::MaybeLocal maybe_column = Nan::To(Nan::Get(object, Nan::New(column_string)).ToLocalChecked()); - Local js_column; - if (!maybe_column.ToLocal(&js_column)) { - Nan::ThrowTypeError("Expected an object with 'row' and 'column' properties."); - return optional{}; - } +Napi::FunctionReference *PointWrapper::constructor; +void PointWrapper::init(Napi::Env env, Napi::Object exports) { + Napi::Function func = DefineClass(env, "Point", { + InstanceAccessor<&PointWrapper::get_row>("row", napi_default_jsproperty), + InstanceAccessor<&PointWrapper::get_column>("column", napi_default_jsproperty), + InstanceMethod<&PointWrapper::inspect>("inspect"), + InstanceMethod<&PointWrapper::inspect>("toString"), + InstanceMethod<&PointWrapper::to_json>("toJSON"), + }); - return Point(number_from_js(js_row), number_from_js(js_column)); + constructor = new Napi::FunctionReference(); + *constructor = Napi::Persistent(func); + exports.Set("Point", func); } -void PointWrapper::init() { - row_string.Reset(Nan::Persistent(Nan::New("row").ToLocalChecked())); - column_string.Reset(Nan::Persistent(Nan::New("column").ToLocalChecked())); - - Local constructor_template = Nan::New(construct); - constructor_template->SetClassName(Nan::New("Point").ToLocalChecked()); - constructor_template->InstanceTemplate()->SetInternalFieldCount(1); - Nan::SetAccessor(constructor_template->InstanceTemplate(), Nan::New(row_string), get_row); - Nan::SetAccessor(constructor_template->InstanceTemplate(), Nan::New(column_string), get_column); - constructor.Reset(Nan::GetFunction(constructor_template).ToLocalChecked()); +Napi::Value PointWrapper::from_point(Napi::Env env, Point point) { + auto wrapped = Napi::External::New(env, &point); + auto values = std::initializer_list { wrapped }; + return PointWrapper::constructor->New(values); } -Local PointWrapper::from_point(Point point) { - Local result; - if (Nan::New(constructor)->NewInstance(Nan::GetCurrentContext()).ToLocal(&result)) { - (new PointWrapper(point))->Wrap(result); - return result; +PointWrapper::PointWrapper(const Napi::CallbackInfo& info) : Napi::ObjectWrap(info) { + if(info[0].IsExternal()) { + auto point = info[0].As>(); + this->point = *point.Data(); } else { - return Nan::Null(); + auto maybe_point = PointWrapper::point_from_js(info[0]); + if(maybe_point) { + this->point = *maybe_point; + } } } -PointWrapper::PointWrapper(Point point) : point(point) {} - -void PointWrapper::construct(const Nan::FunctionCallbackInfo &info) {} - -void PointWrapper::get_row(v8::Local property, const Nan::PropertyCallbackInfo &info) { - PointWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - Point &point = wrapper->point; - info.GetReturnValue().Set(Nan::New(point.row)); +Napi::Value PointWrapper::get_row(const Napi::CallbackInfo &info) { + return Napi::Value::From(info.Env(), point.row); } - -void PointWrapper::get_column(v8::Local property, const Nan::PropertyCallbackInfo &info) { - PointWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - Point &point = wrapper->point; - info.GetReturnValue().Set(Nan::New(point.column)); +Napi::Value PointWrapper::get_column(const Napi::CallbackInfo &info) { + return Napi::Value::From(info.Env(), point.column); +} +Napi::Value PointWrapper::to_json(const Napi::CallbackInfo &info) { + auto json = Napi::Object::New(info.Env()); + json.Set("row", this->point.row); + json.Set("column", this->point.column); + return json; +} +Napi::Value PointWrapper::inspect(const Napi::CallbackInfo &info) { + auto obj = this->to_json(info); + // auto json = Napi::Object::New(info.Env()); + // json.Set("row", this->point.row); + // json.Set("column", this->point.column); + return obj.ToString(); } diff --git a/src/bindings/point-wrapper.h b/src/bindings/point-wrapper.h index fc06b263..d00c7266 100644 --- a/src/bindings/point-wrapper.h +++ b/src/bindings/point-wrapper.h @@ -1,27 +1,24 @@ #ifndef SUPERSTRING_POINT_WRAPPER_H #define SUPERSTRING_POINT_WRAPPER_H -#include "nan.h" -#include "optional.h" +#include "napi.h" #include "point.h" +#include "optional.h" -class PointWrapper : public Nan::ObjectWrap { +class PointWrapper : public Napi::ObjectWrap { public: - static void init(); - static v8::Local from_point(Point point); - static optional point_from_js(v8::Local); - -private: - PointWrapper(Point point); + static void init(Napi::Env env, Napi::Object exports); - static void construct(const Nan::FunctionCallbackInfo &info); - - static void get_row(v8::Local property, - const Nan::PropertyCallbackInfo &info); - - static void get_column(v8::Local property, - const Nan::PropertyCallbackInfo &info); + static Napi::Value from_point(Napi::Env env, Point point); + static optional point_from_js(Napi::Value); + PointWrapper(const Napi::CallbackInfo& info); +private: + static Napi::FunctionReference *constructor; + Napi::Value get_row(const Napi::CallbackInfo &info); + Napi::Value get_column(const Napi::CallbackInfo &info); + Napi::Value inspect(const Napi::CallbackInfo &info); + Napi::Value to_json(const Napi::CallbackInfo &info); Point point; }; diff --git a/src/bindings/range-wrapper.cc b/src/bindings/range-wrapper.cc index b0aaf5ab..cd960f24 100644 --- a/src/bindings/range-wrapper.cc +++ b/src/bindings/range-wrapper.cc @@ -1,64 +1,47 @@ #include "range-wrapper.h" #include "point-wrapper.h" -#include "nan.h" +#include "napi.h" -using namespace v8; +std::optional RangeWrapper::range_from_js(Napi::Value value) { + auto env = value.Env(); -static Nan::Persistent start_string; -static Nan::Persistent end_string; -static Nan::Persistent constructor; - -optional RangeWrapper::range_from_js(Local value) { - Local object; - if (!Nan::To(value).ToLocal(&object)) { - Nan::ThrowTypeError("Expected an object with 'start' and 'end' properties."); - return optional{}; + if (!value.IsObject()) { + Napi::TypeError::New(env, "Expected an object with 'start' and 'end' properties.").ThrowAsJavaScriptException(); + return std::optional(); } + Napi::Object object = value.ToObject(); - auto start = PointWrapper::point_from_js(Nan::Get(object, Nan::New(start_string)).ToLocalChecked()); - auto end = PointWrapper::point_from_js(Nan::Get(object, Nan::New(end_string)).ToLocalChecked()); + auto start = PointWrapper::point_from_js(object.Get("start")); + auto end = PointWrapper::point_from_js(object.Get("end")); if (start && end) { return Range{*start, *end}; } else { - Nan::ThrowTypeError("Expected an object with 'start' and 'end' properties."); - return optional{}; + Napi::TypeError::New(env, "Expected an object with 'start' and 'end' properties.").ThrowAsJavaScriptException(); + return std::optional(); } } -void RangeWrapper::init() { - start_string.Reset(Nan::Persistent(Nan::New("start").ToLocalChecked())); - end_string.Reset(Nan::Persistent(Nan::New("end").ToLocalChecked())); - - Local constructor_template = Nan::New(construct); - constructor_template->SetClassName(Nan::New("Range").ToLocalChecked()); - constructor_template->InstanceTemplate()->SetInternalFieldCount(1); - Nan::SetAccessor(constructor_template->InstanceTemplate(), Nan::New(start_string), get_start); - Nan::SetAccessor(constructor_template->InstanceTemplate(), Nan::New(end_string), get_end); - constructor.Reset(Nan::GetFunction(constructor_template).ToLocalChecked()); +void RangeWrapper::init(Napi::Env env, Napi::Object exports) { + Napi::Function func = DefineClass(env, "Range", { + InstanceAccessor<&RangeWrapper::get_start>("start"), + InstanceAccessor<&RangeWrapper::get_end>("end") + }); + Napi::FunctionReference* constructor = new Napi::FunctionReference(); + *constructor = Napi::Persistent(func); + exports.Set("Range", func); } -Local RangeWrapper::from_range(Range range) { - Local result; - if (Nan::New(constructor)->NewInstance(Nan::GetCurrentContext()).ToLocal(&result)) { - (new RangeWrapper(range))->Wrap(result); - return result; - } else { - return Nan::Null(); +RangeWrapper::RangeWrapper(const Napi::CallbackInfo& info) + : Napi::ObjectWrap(info) { + auto maybe_range = RangeWrapper::range_from_js(info[0]); + if(maybe_range) { + this->range = *maybe_range; } } -RangeWrapper::RangeWrapper(Range range) : range(range) {} - -void RangeWrapper::construct(const Nan::FunctionCallbackInfo &info) {} - -void RangeWrapper::get_start(v8::Local property, const Nan::PropertyCallbackInfo &info) { - RangeWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - Range &range = wrapper->range; - info.GetReturnValue().Set(PointWrapper::from_point(range.start)); +Napi::Value RangeWrapper::get_start(const Napi::CallbackInfo &info) { + return PointWrapper::from_point(info.Env(), range.start); } - -void RangeWrapper::get_end(v8::Local property, const Nan::PropertyCallbackInfo &info) { - RangeWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); - Range &range = wrapper->range; - info.GetReturnValue().Set(PointWrapper::from_point(range.end)); +Napi::Value RangeWrapper::get_end(const Napi::CallbackInfo &info) { + return PointWrapper::from_point(info.Env(), range.end); } diff --git a/src/bindings/range-wrapper.h b/src/bindings/range-wrapper.h index de08dd59..bba5663f 100644 --- a/src/bindings/range-wrapper.h +++ b/src/bindings/range-wrapper.h @@ -1,24 +1,22 @@ #ifndef SUPERSTRING_RANGE_WRAPPER_H #define SUPERSTRING_RANGE_WRAPPER_H -#include "nan.h" -#include "optional.h" +#include "napi.h" #include "point.h" #include "range.h" -class RangeWrapper : public Nan::ObjectWrap { +class RangeWrapper : public Napi::ObjectWrap { public: - static void init(); - static v8::Local from_range(Range); - static optional range_from_js(v8::Local); + static void init(Napi::Env env, Napi::Object exports); + static Napi::Value from_range(Range); + static std::optional range_from_js(Napi::Value); + RangeWrapper(const Napi::CallbackInfo& info); private: - RangeWrapper(Range); - - static void construct(const Nan::FunctionCallbackInfo &); - static void get_start(v8::Local, const Nan::PropertyCallbackInfo &); - static void get_end(v8::Local, const Nan::PropertyCallbackInfo &); + // RangeWrapper(Range); + Napi::Value get_start(const Napi::CallbackInfo &info); + Napi::Value get_end(const Napi::CallbackInfo &info); Range range; }; diff --git a/src/bindings/text-buffer-wrapper.cc b/src/bindings/text-buffer-wrapper.cc index 3c633269..b5a79d8f 100644 --- a/src/bindings/text-buffer-wrapper.cc +++ b/src/bindings/text-buffer-wrapper.cc @@ -210,20 +210,20 @@ void TextBufferWrapper::init(Local exports) { Nan::SetTemplate(prototype_template, Nan::New("characterIndexForPosition").ToLocalChecked(), Nan::New(character_index_for_position), None); Nan::SetTemplate(prototype_template, Nan::New("positionForCharacterIndex").ToLocalChecked(), Nan::New(position_for_character_index), None); Nan::SetTemplate(prototype_template, Nan::New("isModified").ToLocalChecked(), Nan::New(is_modified), None); - Nan::SetTemplate(prototype_template, Nan::New("load").ToLocalChecked(), Nan::New(load), None); - Nan::SetTemplate(prototype_template, Nan::New("baseTextMatchesFile").ToLocalChecked(), Nan::New(base_text_matches_file), None); - Nan::SetTemplate(prototype_template, Nan::New("save").ToLocalChecked(), Nan::New(save), None); + Nan::SetTemplate(prototype_template, Nan::New("_load").ToLocalChecked(), Nan::New(load), None); + Nan::SetTemplate(prototype_template, Nan::New("_baseTextMatchesFile").ToLocalChecked(), Nan::New(base_text_matches_file), None); + Nan::SetTemplate(prototype_template, Nan::New("_save").ToLocalChecked(), Nan::New(save), None); Nan::SetTemplate(prototype_template, Nan::New("loadSync").ToLocalChecked(), Nan::New(load_sync), None); Nan::SetTemplate(prototype_template, Nan::New("serializeChanges").ToLocalChecked(), Nan::New(serialize_changes), None); Nan::SetTemplate(prototype_template, Nan::New("deserializeChanges").ToLocalChecked(), Nan::New(deserialize_changes), None); Nan::SetTemplate(prototype_template, Nan::New("reset").ToLocalChecked(), Nan::New(reset), None); Nan::SetTemplate(prototype_template, Nan::New("baseTextDigest").ToLocalChecked(), Nan::New(base_text_digest), None); - Nan::SetTemplate(prototype_template, Nan::New("find").ToLocalChecked(), Nan::New(find), None); - Nan::SetTemplate(prototype_template, Nan::New("findSync").ToLocalChecked(), Nan::New(find_sync), None); - Nan::SetTemplate(prototype_template, Nan::New("findAll").ToLocalChecked(), Nan::New(find_all), None); - Nan::SetTemplate(prototype_template, Nan::New("findAllSync").ToLocalChecked(), Nan::New(find_all_sync), None); + Nan::SetTemplate(prototype_template, Nan::New("_find").ToLocalChecked(), Nan::New(find), None); + Nan::SetTemplate(prototype_template, Nan::New("_findSync").ToLocalChecked(), Nan::New(find_sync), None); + Nan::SetTemplate(prototype_template, Nan::New("_findAll").ToLocalChecked(), Nan::New(find_all), None); + Nan::SetTemplate(prototype_template, Nan::New("_findAllSync").ToLocalChecked(), Nan::New(find_all_sync), None); Nan::SetTemplate(prototype_template, Nan::New("findAndMarkAllSync").ToLocalChecked(), Nan::New(find_and_mark_all_sync), None); - Nan::SetTemplate(prototype_template, Nan::New("findWordsWithSubsequenceInRange").ToLocalChecked(), Nan::New(find_words_with_subsequence_in_range), None); + Nan::SetTemplate(prototype_template, Nan::New("_findWordsWithSubsequenceInRange").ToLocalChecked(), Nan::New(find_words_with_subsequence_in_range), None); Nan::SetTemplate(prototype_template, Nan::New("getDotGraph").ToLocalChecked(), Nan::New(dot_graph), None); Nan::SetTemplate(prototype_template, Nan::New("getSnapshot").ToLocalChecked(), Nan::New(get_snapshot), None); RegexWrapper::init(); @@ -387,11 +387,7 @@ static Local encode_ranges(const vector &ranges) { auto length = ranges.size() * 4; auto buffer = v8::ArrayBuffer::New(v8::Isolate::GetCurrent(), length * sizeof(uint32_t)); auto result = v8::Uint32Array::New(buffer, 0, length); - #if (V8_MAJOR_VERSION < 8) - auto data = buffer->GetContents().Data(); - #else - auto data = buffer->GetBackingStore()->Data(); - #endif + auto data = buffer->GetBackingStore()->Data(); memcpy(data, ranges.data(), length * sizeof(uint32_t)); return result; } @@ -615,11 +611,7 @@ void TextBufferWrapper::find_words_with_subsequence_in_range(const Nan::Function } auto positions_buffer = v8::ArrayBuffer::New(v8::Isolate::GetCurrent(), positions_buffer_size); - #if (V8_MAJOR_VERSION < 8) - uint32_t *positions_data = reinterpret_cast(positions_buffer->GetContents().Data()); - #else - uint32_t *positions_data = reinterpret_cast(positions_buffer->GetBackingStore()->Data()); - #endif + uint32_t *positions_data = reinterpret_cast(positions_buffer->GetBackingStore()->Data()); uint32_t positions_array_index = 0; for (size_t i = 0; i < result.size() && i < max_count; i++) { @@ -943,11 +935,7 @@ void TextBufferWrapper::load(const Nan::FunctionCallbackInfo &info) { if (!force && text_buffer.is_modified()) { Local argv[] = {Nan::Null(), Nan::Null()}; auto callback = info[0].As(); - #if (V8_MAJOR_VERSION > 9 || (V8_MAJOR_VERSION == 9 && V8_MINOR_VERION > 4)) - Nan::Call(callback, callback->GetCreationContext().ToLocalChecked()->Global(), 2, argv); - #else - Nan::Call(callback, callback->CreationContext()->Global(), 2, argv); - #endif + Nan::Call(callback, callback->CreationContext()->Global(), 2, argv); return; } @@ -1052,11 +1040,7 @@ void TextBufferWrapper::base_text_matches_file(const Nan::FunctionCallbackInfo argv[] = {Nan::Null(), Nan::New(result)}; auto callback = info[0].As(); - #if (V8_MAJOR_VERSION > 9 || (V8_MAJOR_VERSION == 9 && V8_MINOR_VERION > 4)) - Nan::Call(callback, callback->GetCreationContext().ToLocalChecked()->Global(), 2, argv); - #else - Nan::Call(callback, callback->CreationContext()->Global(), 2, argv); - #endif + Nan::Call(callback, callback->CreationContext()->Global(), 2, argv); } } diff --git a/src/core/patch.cc b/src/core/patch.cc index 8702f9b3..db5e8886 100644 --- a/src/core/patch.cc +++ b/src/core/patch.cc @@ -477,8 +477,10 @@ Patch Patch::invert() { // Mutations bool Patch::splice(Point new_splice_start, - Point new_deletion_extent, Point new_insertion_extent, - optional &&deleted_text, optional &&inserted_text, + Point new_deletion_extent, + Point new_insertion_extent, + optional &&deleted_text, + optional &&inserted_text, uint32_t deleted_text_size) { if (new_deletion_extent.is_zero() && new_insertion_extent.is_zero()) return true; diff --git a/test/js/patch.test.js b/test/js/patch.test.js index 30862d84..3f4c722f 100644 --- a/test/js/patch.test.js +++ b/test/js/patch.test.js @@ -29,8 +29,6 @@ describe('Patch', function () { newEnd: {row: 1, column: 13} } ]) - - patch.delete(); }) it('honors the mergeAdjacentChanges option set to true', function () { @@ -56,8 +54,6 @@ describe('Patch', function () { newStart: {row: 0, column: 5}, newEnd: {row: 0, column: 11} } ]) - - patch.delete(); }) describe('.compose', () => { @@ -95,11 +91,6 @@ describe('Patch', function () { assert.throws(() => Patch.compose([{}, {}])) assert.throws(() => Patch.compose([1, 'a'])) - - for (let patch of patches) - patch.delete(); - - composedPatch.delete(); }) it('throws an Error if the patches do not apply', () => { @@ -169,10 +160,6 @@ describe('Patch', function () { newStart: {row: 0, column: 9}, newEnd: {row: 0, column: 14} } ]) - - patch.delete(); - invertedPatch.delete(); - patch2.delete(); }) it('can copy patches', function () { @@ -186,8 +173,6 @@ describe('Patch', function () { patch2.splice({row: 0, column: 10}, {row: 0, column: 5}, {row: 0, column: 5}) assert.deepEqual(patch2.copy().getChanges(), patch2.getChanges()) - patch.delete(); - patch2.delete(); }) it('can serialize/deserialize patches', () => { @@ -207,9 +192,6 @@ describe('Patch', function () { oldText: 'hello', newText: 'world' }]) - - patch1.delete(); - patch2.delete(); }) it('removes a change when it becomes empty', () => { @@ -368,8 +350,6 @@ describe('Patch', function () { assert.deepEqual(patchCopy2.getChanges(), patch.getChanges(), seedMessage) assert.deepEqual(patchCopy2.changeForOldPosition(oldPoint), patch.changeForOldPosition(oldPoint), seedMessage) } - - patch.delete(); } })