Skip to content

Instantly share code, notes, and snippets.

@harpagon210
Created May 12, 2020 16:23
Show Gist options
  • Save harpagon210/deefb4fc88b2bc22756e3cb011762e4a to your computer and use it in GitHub Desktop.
Save harpagon210/deefb4fc88b2bc22756e3cb011762e4a to your computer and use it in GitHub Desktop.
nodejs native module JSON parser/stringifier (native implementation vs rapidjson)
#include "JSON.h"
#include <iostream>
#include <chrono>
Napi::Value JSON::DocumentToValue(Napi::Env env, rapidjson::Value document)
{
if (document.IsString())
{
return Napi::String::New(env, document.GetString());
}
else if (document.IsBool())
{
return Napi::Boolean::New(env, document.GetBool());
}
else if (document.IsDouble())
{
return Napi::Number::New(env, document.GetDouble());
}
else if (document.IsNull())
{
return env.Null();
}
else if (document.IsArray())
{
rapidjson::Value::Array doc = document.GetArray();
int length = doc.Size();
Napi::Array array = Napi::Array::New(env, length);
int i;
for (i = 0; i < length; i++)
{
if (doc[i].IsString())
{
array.Set(i, Napi::String::New(env, doc[i].GetString()));
}
else if (doc[i].IsBool())
{
array.Set(i, Napi::Boolean::New(env, doc[i].GetBool()));
}
else if (doc[i].IsDouble())
{
array.Set(i, Napi::Number::New(env, doc[i].GetDouble()));
}
else if (doc[i].IsArray())
{
array.Set(i, JSON::DocumentToValue(env, doc[i].GetArray()));
}
else if (doc[i].IsObject())
{
array.Set(i, JSON::DocumentToValue(env, doc[i].GetObject()));
}
else
{
array.Set(i, env.Null());
}
}
return array;
}
else if (document.IsObject())
{
Napi::Object obj = Napi::Object::New(env);
for (rapidjson::Value::MemberIterator itr = document.MemberBegin(); itr != document.MemberEnd(); ++itr)
{
std::string key = itr->name.GetString();
if (itr->value.IsString())
{
obj.Set(key, Napi::String::New(env, itr->value.GetString()));
}
else if (itr->value.IsBool())
{
obj.Set(key, Napi::Boolean::New(env, itr->value.GetBool()));
}
else if (itr->value.IsDouble())
{
obj.Set(key, Napi::Number::New(env, itr->value.GetDouble()));
}
else if (itr->value.IsArray())
{
obj.Set(key, JSON::DocumentToValue(env, itr->value.GetArray()));
}
else if (itr->value.IsObject())
{
obj.Set(key, JSON::DocumentToValue(env, itr->value.GetObject()));
} else
{
obj.Set(key, env.Null());
}
}
return obj;
}
}
Napi::Value JSON::Parse(Napi::Env env, std::string json_string)
{
Napi::Value value = Napi::Value();
rapidjson::Document document;
document.Parse(json_string.c_str());
if (!document.HasParseError())
{
value = JSON::DocumentToValue(env, document.GetObject());
}
return value;
}
Napi::Value JSON::ParseNative(Napi::Env env, Napi::String json_string)
{
Napi::Object json = env.Global().Get("JSON").As<Napi::Object>();
Napi::Function parse = json.Get("parse").As<Napi::Function>();
Napi::Value val = parse.Call(json, {json_string});
return val;
}
Napi::Value JSON::StringifyNative(Napi::Env env, Napi::Value json_object)
{
Napi::Object json = env.Global().Get("JSON").As<Napi::Object>();
Napi::Function stringify = json.Get("stringify").As<Napi::Function>();
return stringify.Call(json, {json_object});
}
void JSON::ValueToString(rapidjson::Writer<rapidjson::StringBuffer> &writer, Napi::Value value)
{
if (value.IsNull())
{
writer.Null();
}
else if (value.IsUndefined())
{
// don't stringify
}
else if (value.IsArray())
{
writer.StartArray();
Napi::Array array = value.As<Napi::Array>();
for (uint32_t i = 0; i < array.Length(); i++)
{
Napi::Value val = array.Get(i);
JSON::ValueToString(writer, val);
}
writer.EndArray();
}
else if (value.IsObject())
{
writer.StartObject();
Napi::Object obj = value.As<Napi::Object>();
Napi::Array props = obj.GetPropertyNames();
for (uint32_t i = 0; i < props.Length(); i++)
{
std::string key = props.Get(i).ToString();
Napi::Value val = obj.Get(key);
if (!val.IsUndefined())
{
writer.String(key.c_str());
JSON::ValueToString(writer, val);
}
}
writer.EndObject();
}
else if (value.IsBoolean())
{
Napi::Boolean val = value.As<Napi::Boolean>();
writer.Bool(val.ToBoolean());
}
else if (value.IsNumber())
{
Napi::Number val = value.As<Napi::Number>();
writer.Double(val.DoubleValue());
}
else
{
Napi::String val = value.As<Napi::String>();
std::string str = val.ToString();
writer.String(str.c_str());
}
}
std::string JSON::Stringify(Napi::Value json_object)
{
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
JSON::ValueToString(writer, json_object);
return buffer.GetString();
}
#ifndef JSON_H
#define JSON_H
#include <napi.h>
#include "thirdparty/rapidjson/document.h"
#include "thirdparty/rapidjson/writer.h"
#include "thirdparty/rapidjson/stringbuffer.h"
class JSON
{
public:
static Napi::Value DocumentToValue(Napi::Env env, rapidjson::Value document);
static Napi::Value ParseNative(Napi::Env env, Napi::String json_string);
static Napi::Value Parse(Napi::Env env, std::string json_string);
static void ValueToString(rapidjson::Writer<rapidjson::StringBuffer> &writer, Napi::Value value);
static std::string Stringify(Napi::Value json_object);
static Napi::Value StringifyNative(Napi::Env env, Napi::Value json_object);
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment