#! /usr/bin/env node 'use strict' const fs = require('fs'); const path = require('path'); const args = process.argv.slice(2); const dir = args[0]; if (!dir) { console.log('Usage: node ' + path.basename(__filename) + ' '); process.exit(1); } const NodeApiVersion = require('../package.json').version; const disable = args[1]; if (disable != "--disable" && dir != "--disable") { var ConfigFileOperations = { 'package.json': [ [ /([ ]*)"dependencies": {/g, '$1"dependencies": {\n$1 "node-addon-api": "' + NodeApiVersion + '",'], [ /[ ]*"nan": *"[^"]+"(,|)[\n\r]/g, '' ] ], 'binding.gyp': [ [ /([ ]*)'include_dirs': \[/g, '$1\'include_dirs\': [\n$1 \'\s+(\w+)\s*=\s*Nan::New\([\w\d:]+\);(?:\w+->Reset\(\1\))?\s+\1->SetClassName\(Nan::String::New\("(\w+)"\)\);/g, 'Napi::Function $1 = DefineClass(env, "$2", {' ], [ /Local\s+(\w+)\s*=\s*Nan::New\([\w\d:]+\);\s+(\w+)\.Reset\((\1)\);\s+\1->SetClassName\((Nan::String::New|Nan::New<(v8::)*String>)\("(.+?)"\)\);/g, 'Napi::Function $1 = DefineClass(env, "$6", {'], [ /Local\s+(\w+)\s*=\s*Nan::New\([\w\d:]+\);(?:\w+->Reset\(\1\))?\s+\1->SetClassName\(Nan::String::New\("(\w+)"\)\);/g, 'Napi::Function $1 = DefineClass(env, "$2", {' ], [ /Nan::New\(([\w\d:]+)\)->GetFunction\(\)/g, 'Napi::Function::New(env, $1)' ], [ /Nan::New\(([\w\d:]+)\)->GetFunction()/g, 'Napi::Function::New(env, $1);' ], [ /Nan::New\(([\w\d:]+)\)/g, 'Napi::Function::New(env, $1)' ], [ /Nan::New\(([\w\d:]+)\)/g, 'Napi::Function::New(env, $1)' ], // FunctionTemplate to FunctionReference [ /Nan::Persistent<(v8::)*FunctionTemplate>/g, 'Napi::FunctionReference' ], [ /Nan::Persistent<(v8::)*Function>/g, 'Napi::FunctionReference' ], [ /v8::Local/g, 'Napi::FunctionReference' ], [ /Local/g, 'Napi::FunctionReference' ], [ /v8::FunctionTemplate/g, 'Napi::FunctionReference' ], [ /FunctionTemplate/g, 'Napi::FunctionReference' ], [ /([ ]*)Nan::SetPrototypeMethod\(\w+, "(\w+)", (\w+)\);/g, '$1InstanceMethod("$2", &$3),' ], [ /([ ]*)(?:\w+\.Reset\(\w+\);\s+)?\(target\)\.Set\("(\w+)",\s*Nan::GetFunction\((\w+)\)\);/gm, '});\n\n' + '$1constructor = Napi::Persistent($3);\n' + '$1constructor.SuppressDestruct();\n' + '$1target.Set("$2", $3);' ], // TODO: Other attribute combinations [ /static_cast\(ReadOnly\s*\|\s*DontDelete\)/gm, 'static_cast(napi_enumerable | napi_configurable)' ], [ /([\w\d:<>]+?)::Cast\((.+?)\)/g, '$2.As<$1>()' ], [ /\*Nan::Utf8String\(([^)]+)\)/g, '$1->As().Utf8Value().c_str()' ], [ /Nan::Utf8String +(\w+)\(([^)]+)\)/g, 'std::string $1 = $2.As()' ], [ /Nan::Utf8String/g, 'std::string' ], [ /v8::String::Utf8Value (.+?)\((.+?)\)/g, 'Napi::String $1(env, $2)' ], [ /String::Utf8Value (.+?)\((.+?)\)/g, 'Napi::String $1(env, $2)' ], [ /\.length\(\)/g, '.Length()' ], [ /Nan::MakeCallback\(([^,]+),[\s\\]+([^,]+),/gm, '$2.MakeCallback($1,' ], [ /class\s+(\w+)\s*:\s*public\s+Nan::ObjectWrap/g, 'class $1 : public Napi::ObjectWrap<$1>' ], [ /(\w+)\(([^\)]*)\)\s*:\s*Nan::ObjectWrap\(\)\s*(,)?/gm, '$1($2) : Napi::ObjectWrap<$1>()$3' ], // HandleOKCallback to OnOK [ /HandleOKCallback/g, 'OnOK' ], // HandleErrorCallback to OnError [ /HandleErrorCallback/g, 'OnError' ], // ex. .As() to .As() [ /\.As\(\)/g, '.As()' ], [ /\.As<(Value|Boolean|String|Number|Object|Array|Symbol|External|Function)>\(\)/g, '.As()' ], // ex. Nan::New(info[0]) to Napi::Number::New(info[0]) [ /Nan::New<(v8::)*Integer>\((.+?)\)/g, 'Napi::Number::New(env, $2)' ], [ /Nan::New\(([0-9\.]+)\)/g, 'Napi::Number::New(env, $1)' ], [ /Nan::New<(v8::)*String>\("(.+?)"\)/g, 'Napi::String::New(env, "$2")' ], [ /Nan::New\("(.+?)"\)/g, 'Napi::String::New(env, "$1")' ], [ /Nan::New<(v8::)*(.+?)>\(\)/g, 'Napi::$2::New(env)' ], [ /Nan::New<(.+?)>\(\)/g, 'Napi::$1::New(env)' ], [ /Nan::New<(v8::)*(.+?)>\(/g, 'Napi::$2::New(env, ' ], [ /Nan::New<(.+?)>\(/g, 'Napi::$1::New(env, ' ], [ /Nan::NewBuffer\(/g, 'Napi::Buffer::New(env, ' ], // TODO: Properly handle this [ /Nan::New\(/g, 'Napi::New(env, ' ], [ /\.IsInt32\(\)/g, '.IsNumber()' ], [ /->IsInt32\(\)/g, '.IsNumber()' ], [ /(.+?)->BooleanValue\(\)/g, '$1.As().Value()' ], [ /(.+?)->Int32Value\(\)/g, '$1.As().Int32Value()' ], [ /(.+?)->Uint32Value\(\)/g, '$1.As().Uint32Value()' ], [ /(.+?)->IntegerValue\(\)/g, '$1.As().Int64Value()' ], [ /(.+?)->NumberValue\(\)/g, '$1.As().DoubleValue()' ], // ex. Nan::To(info[0]) to info[0].Value() [ /Nan::To\((.+?)\)/g, '$2.To()' ], [ /Nan::To<(Boolean|String|Number|Object|Array|Symbol|Function)>\((.+?)\)/g, '$2.To()' ], // ex. Nan::To(info[0]) to info[0].As().Value() [ /Nan::To\((.+?)\)/g, '$1.As().Value()' ], // ex. Nan::To(info[0]) to info[0].As().Int32Value() [ /Nan::To\((.+?)\)/g, '$1.As().Int32Value()' ], // ex. Nan::To(info[0]) to info[0].As().Int32Value() [ /Nan::To\((.+?)\)/g, '$1.As().Int32Value()' ], // ex. Nan::To(info[0]) to info[0].As().Uint32Value() [ /Nan::To\((.+?)\)/g, '$1.As().Uint32Value()' ], // ex. Nan::To(info[0]) to info[0].As().Int64Value() [ /Nan::To\((.+?)\)/g, '$1.As().Int64Value()' ], // ex. Nan::To(info[0]) to info[0].As().FloatValue() [ /Nan::To\((.+?)\)/g, '$1.As().FloatValue()' ], // ex. Nan::To(info[0]) to info[0].As().DoubleValue() [ /Nan::To\((.+?)\)/g, '$1.As().DoubleValue()' ], [ /Nan::New\((\w+)\)->HasInstance\((\w+)\)/g, '$2.InstanceOf($1.Value())' ], [ /Nan::Has\(([^,]+),\s*/gm, '($1).Has(' ], [ /\.Has\([\s|\\]*Nan::New<(v8::)*String>\(([^)]+)\)\)/gm, '.Has($1)' ], [ /\.Has\([\s|\\]*Nan::New\(([^)]+)\)\)/gm, '.Has($1)' ], [ /Nan::Get\(([^,]+),\s*/gm, '($1).Get(' ], [ /\.Get\([\s|\\]*Nan::New<(v8::)*String>\(([^)]+)\)\)/gm, '.Get($1)' ], [ /\.Get\([\s|\\]*Nan::New\(([^)]+)\)\)/gm, '.Get($1)' ], [ /Nan::Set\(([^,]+),\s*/gm, '($1).Set(' ], [ /\.Set\([\s|\\]*Nan::New<(v8::)*String>\(([^)]+)\)\s*,/gm, '.Set($1,' ], [ /\.Set\([\s|\\]*Nan::New\(([^)]+)\)\s*,/gm, '.Set($1,' ], // ex. node::Buffer::HasInstance(info[0]) to info[0].IsBuffer() [ /node::Buffer::HasInstance\((.+?)\)/g, '$1.IsBuffer()' ], // ex. node::Buffer::Length(info[0]) to info[0].Length() [ /node::Buffer::Length\((.+?)\)/g, '$1.As>().Length()' ], // ex. node::Buffer::Data(info[0]) to info[0].Data() [ /node::Buffer::Data\((.+?)\)/g, '$1.As>().Data()' ], [ /Nan::CopyBuffer\(/g, 'Napi::Buffer::Copy(env, ' ], // Nan::AsyncQueueWorker(worker) [ /Nan::AsyncQueueWorker\((.+)\);/g, '$1.Queue();' ], [ /Nan::(Undefined|Null|True|False)\(\)/g, 'env.$1()' ], // Nan::ThrowError(error) to Napi::Error::New(env, error).ThrowAsJavaScriptException() [ /([ ]*)return Nan::Throw(\w*?)Error\((.+?)\);/g, '$1Napi::$2Error::New(env, $3).ThrowAsJavaScriptException();\n$1return env.Null();' ], [ /Nan::Throw(\w*?)Error\((.+?)\);\n(\s*)return;/g, 'Napi::$1Error::New(env, $2).ThrowAsJavaScriptException();\n$3return env.Null();' ], [ /Nan::Throw(\w*?)Error\((.+?)\);/g, 'Napi::$1Error::New(env, $2).ThrowAsJavaScriptException();\n' ], // Nan::RangeError(error) to Napi::RangeError::New(env, error) [ /Nan::(\w*?)Error\((.+)\)/g, 'Napi::$1Error::New(env, $2)' ], [ /Nan::Set\((.+?),\n* *(.+?),\n* *(.+?),\n* *(.+?)\)/g, '$1.Set($2, $3, $4)' ], [ /Nan::(Escapable)?HandleScope\s+(\w+)\s*;/g, 'Napi::$1HandleScope $2(env);' ], [ /Nan::(Escapable)?HandleScope/g, 'Napi::$1HandleScope' ], [ /Nan::ForceSet\(([^,]+), ?/g, '$1->DefineProperty(' ], [ /\.ForceSet\(Napi::String::New\(env, "(\w+)"\),\s*?/g, '.DefineProperty("$1", ' ], // [ /Nan::GetPropertyNames\(([^,]+)\)/, '$1->GetPropertyNames()' ], [ /Nan::Equals\(([^,]+),/g, '$1.StrictEquals(' ], [ /(.+)->Set\(/g, '$1.Set\(' ], [ /Nan::Callback/g, 'Napi::FunctionReference' ], [ /Nan::Persistent/g, 'Napi::ObjectReference' ], [ /Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target/g, 'Napi::Env& env, Napi::Object& target' ], [ /(\w+)\*\s+(\w+)\s*=\s*Nan::ObjectWrap::Unwrap<\w+>\(info\.This\(\)\);/g, '$1* $2 = this;' ], [ /Nan::ObjectWrap::Unwrap<(\w+)>\((.*)\);/g, '$2.Unwrap<$1>();' ], [ /Nan::NAN_METHOD_RETURN_TYPE/g, 'void' ], [ /NAN_INLINE/g, 'inline' ], [ /Nan::NAN_METHOD_ARGS_TYPE/g, 'const Napi::CallbackInfo&' ], [ /NAN_METHOD\(([\w\d:]+?)\)/g, 'Napi::Value $1(const Napi::CallbackInfo& info)'], [ /static\s*NAN_GETTER\(([\w\d:]+?)\)/g, 'Napi::Value $1(const Napi::CallbackInfo& info)' ], [ /NAN_GETTER\(([\w\d:]+?)\)/g, 'Napi::Value $1(const Napi::CallbackInfo& info)' ], [ /static\s*NAN_SETTER\(([\w\d:]+?)\)/g, 'void $1(const Napi::CallbackInfo& info, const Napi::Value& value)' ], [ /NAN_SETTER\(([\w\d:]+?)\)/g, 'void $1(const Napi::CallbackInfo& info, const Napi::Value& value)' ], [ /void Init\((v8::)*Local<(v8::)*Object> exports\)/g, 'Napi::Object Init(Napi::Env env, Napi::Object exports)' ], [ /NAN_MODULE_INIT\(([\w\d:]+?)\);/g, 'Napi::Object $1(Napi::Env env, Napi::Object exports);' ], [ /NAN_MODULE_INIT\(([\w\d:]+?)\)/g, 'Napi::Object $1(Napi::Env env, Napi::Object exports)' ], [ /::(Init(?:ialize)?)\(target\)/g, '::$1(env, target, module)' ], [ /constructor_template/g, 'constructor' ], [ /Nan::FunctionCallbackInfo<(v8::)?Value>[ ]*& [ ]*info\)[ ]*{\n*([ ]*)/gm, 'Napi::CallbackInfo& info) {\n$2Napi::Env env = info.Env();\n$2' ], [ /Nan::FunctionCallbackInfo<(v8::)*Value>\s*&\s*info\);/g, 'Napi::CallbackInfo& info);' ], [ /Nan::FunctionCallbackInfo<(v8::)*Value>\s*&/g, 'Napi::CallbackInfo&' ], [ /Buffer::HasInstance\(([^)]+)\)/g, '$1.IsBuffer()' ], [ /info\[(\d+)\]->/g, 'info[$1].' ], [ /info\[([\w\d]+)\]->/g, 'info[$1].' ], [ /info\.This\(\)->/g, 'info.This().' ], [ /->Is(Object|String|Int32|Number)\(\)/g, '.Is$1()' ], [ /info.GetReturnValue\(\).SetUndefined\(\)/g, 'return env.Undefined()' ], [ /info\.GetReturnValue\(\)\.Set\(((\n|.)+?)\);/g, 'return $1;' ], // ex. Local to Napi::Value [ /v8::Local/g, 'Napi::$1' ], [ /Local<(Value|Boolean|String|Number|Object|Array|Symbol|External|Function)>/g, 'Napi::$1' ], // Declare an env in helper functions that take a Napi::Value [ /(\w+)\(Napi::Value (\w+)(,\s*[^\()]+)?\)\s*{\n*([ ]*)/gm, '$1(Napi::Value $2$3) {\n$4Napi::Env env = $2.Env();\n$4' ], // delete #include and/or [ /#include +(<|")(?:node|nan).h("|>)/g, "#include $1napi.h$2\n#include $1uv.h$2" ], // NODE_MODULE to NODE_API_MODULE [ /NODE_MODULE/g, 'NODE_API_MODULE' ], [ /Nan::/g, 'Napi::' ], [ /nan.h/g, 'napi.h' ], // delete .FromJust() [ /\.FromJust\(\)/g, '' ], // delete .ToLocalCheck() [ /\.ToLocalChecked\(\)/g, '' ], [ /^.*->SetInternalFieldCount\(.*$/gm, '' ], // replace using node; and/or using v8; to using Napi; [ /using (node|v8);/g, 'using Napi;' ], [ /using namespace (node|Nan|v8);/g, 'using namespace Napi;' ], // delete using v8::Local; [ /using v8::Local;\n/g, '' ], // replace using v8::XXX; with using Napi::XXX [ /using v8::([A-Za-z]+);/g, 'using Napi::$1;' ], ]; var paths = listFiles(dir); paths.forEach(function(dirEntry) { var filename = dirEntry.split('\\').pop().split('/').pop(); // Check whether the file is a source file or a config file // then execute function accordingly var sourcePattern = /.+\.h|.+\.cc|.+\.cpp/; if (sourcePattern.test(filename)) { convertFile(dirEntry, SourceFileOperations); } else if (ConfigFileOperations[filename] != null) { convertFile(dirEntry, ConfigFileOperations[filename]); } }); function listFiles(dir, filelist) { var files = fs.readdirSync(dir); filelist = filelist || []; files.forEach(function(file) { if (file === 'node_modules') { return } if (fs.statSync(path.join(dir, file)).isDirectory()) { filelist = listFiles(path.join(dir, file), filelist); } else { filelist.push(path.join(dir, file)); } }); return filelist; } function convert(content, operations) { for (let i = 0; i < operations.length; i ++) { let operation = operations[i]; content = content.replace(operation[0], operation[1]); } return content; } function convertFile(fileName, operations) { fs.readFile(fileName, "utf-8", function (err, file) { if (err) throw err; file = convert(file, operations); fs.writeFile(fileName, file, function(err){ if (err) throw err; }); }); }