Add more Value APIs

Summary:
Adds:
 - callAsConstructor
 - Ability to provide `this` object to callAsFunction
 - getPropertyNames() now returns Strings (which can be converted by the caller to std::string if they want).

Fixes:
 - double free issue with the String move constructor

Reviewed By: lexs

Differential Revision: D3515398

fbshipit-source-id: afa1342044e41fdd833dd27b8a244a58d4078442
This commit is contained in:
Andy Street 2016-07-06 06:30:25 -07:00 committed by Facebook Github Bot 5
parent 43231c0524
commit 8a0640716b
2 changed files with 44 additions and 11 deletions

View File

@ -73,19 +73,41 @@ Object::operator Value() const {
} }
Value Object::callAsFunction(std::initializer_list<JSValueRef> args) const { Value Object::callAsFunction(std::initializer_list<JSValueRef> args) const {
return callAsFunction(args.size(), args.begin()); return callAsFunction(nullptr, args.size(), args.begin());
}
Value Object::callAsFunction(const Object& thisObj, std::initializer_list<JSValueRef> args) const {
return callAsFunction((JSObjectRef) thisObj, args.size(), args.begin());
} }
Value Object::callAsFunction(int nArgs, const JSValueRef args[]) const { Value Object::callAsFunction(int nArgs, const JSValueRef args[]) const {
return callAsFunction(nullptr, nArgs, args);
}
Value Object::callAsFunction(const Object& thisObj, int nArgs, const JSValueRef args[]) const {
return callAsFunction((JSObjectRef) thisObj, nArgs, args);
}
Value Object::callAsFunction(JSObjectRef thisObj, int nArgs, const JSValueRef args[]) const {
JSValueRef exn; JSValueRef exn;
JSValueRef result = JSObjectCallAsFunction(m_context, m_obj, NULL, nArgs, args, &exn); JSValueRef result = JSObjectCallAsFunction(m_context, m_obj, thisObj, nArgs, args, &exn);
if (!result) { if (!result) {
std::string exceptionText = Value(m_context, exn).toString().str(); std::string exceptionText = Value(m_context, exn).toString().str();
throwJSExecutionException("Exception calling JS function: %s", exceptionText.c_str()); throwJSExecutionException("Exception calling object as function: %s", exceptionText.c_str());
} }
return Value(m_context, result); return Value(m_context, result);
} }
Object Object::callAsConstructor(std::initializer_list<JSValueRef> args) const {
JSValueRef exn;
JSObjectRef result = JSObjectCallAsConstructor(m_context, m_obj, args.size(), args.begin(), &exn);
if (!result) {
std::string exceptionText = Value(m_context, exn).toString().str();
throwJSExecutionException("Exception calling object as constructor: %s", exceptionText.c_str());
}
return Object(m_context, result);
}
Value Object::getProperty(const String& propName) const { Value Object::getProperty(const String& propName) const {
JSValueRef exn; JSValueRef exn;
JSValueRef property = JSObjectGetProperty(m_context, m_obj, propName, &exn); JSValueRef property = JSObjectGetProperty(m_context, m_obj, propName, &exn);
@ -123,13 +145,13 @@ void Object::setProperty(const char *propName, const Value& value) const {
setProperty(String(propName), value); setProperty(String(propName), value);
} }
std::vector<std::string> Object::getPropertyNames() const { std::vector<String> Object::getPropertyNames() const {
std::vector<std::string> names;
auto namesRef = JSObjectCopyPropertyNames(m_context, m_obj); auto namesRef = JSObjectCopyPropertyNames(m_context, m_obj);
size_t count = JSPropertyNameArrayGetCount(namesRef); size_t count = JSPropertyNameArrayGetCount(namesRef);
std::vector<String> names;
names.reserve(count);
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
auto string = String::ref(JSPropertyNameArrayGetNameAtIndex(namesRef, i)); names.emplace_back(String::ref(JSPropertyNameArrayGetNameAtIndex(namesRef, i)));
names.emplace_back(string.str());
} }
JSPropertyNameArrayRelease(namesRef); JSPropertyNameArrayRelease(namesRef);
return names; return names;

View File

@ -53,7 +53,9 @@ public:
String(String&& other) : String(String&& other) :
m_string(other.m_string) m_string(other.m_string)
{} {
other.m_string = nullptr;
}
String(const String& other) : String(const String& other) :
m_string(other.m_string) m_string(other.m_string)
@ -168,15 +170,18 @@ public:
} }
Value callAsFunction(std::initializer_list<JSValueRef> args) const; Value callAsFunction(std::initializer_list<JSValueRef> args) const;
Value callAsFunction(const Object& thisObj, std::initializer_list<JSValueRef> args) const;
Value callAsFunction(int nArgs, const JSValueRef args[]) const; Value callAsFunction(int nArgs, const JSValueRef args[]) const;
Value callAsFunction(const Object& thisObj, int nArgs, const JSValueRef args[]) const;
Object callAsConstructor(std::initializer_list<JSValueRef> args) const;
Value getProperty(const String& propName) const; Value getProperty(const String& propName) const;
Value getProperty(const char *propName) const; Value getProperty(const char *propName) const;
Value getPropertyAtIndex(unsigned index) const; Value getPropertyAtIndex(unsigned index) const;
void setProperty(const String& propName, const Value& value) const; void setProperty(const String& propName, const Value& value) const;
void setProperty(const char *propName, const Value& value) const; void setProperty(const char *propName, const Value& value) const;
std::vector<std::string> getPropertyNames() const; std::vector<String> getPropertyNames() const;
std::unordered_map<std::string, std::string> toJSONMap() const; std::unordered_map<std::string, std::string> toJSONMap() const;
void makeProtected() { void makeProtected() {
@ -186,6 +191,10 @@ public:
} }
} }
JSContextRef context() const {
return m_context;
}
static Object getGlobalObject(JSContextRef ctx) { static Object getGlobalObject(JSContextRef ctx) {
auto globalObj = JSContextGetGlobalObject(ctx); auto globalObj = JSContextGetGlobalObject(ctx);
return Object(ctx, globalObj); return Object(ctx, globalObj);
@ -200,6 +209,8 @@ private:
JSContextRef m_context; JSContextRef m_context;
JSObjectRef m_obj; JSObjectRef m_obj;
bool m_isProtected = false; bool m_isProtected = false;
Value callAsFunction(JSObjectRef thisObj, int nArgs, const JSValueRef args[]) const;
}; };
class Value : public noncopyable { class Value : public noncopyable {
@ -265,8 +276,8 @@ public:
std::string toJSONString(unsigned indent = 0) const throw(JSException); std::string toJSONString(unsigned indent = 0) const throw(JSException);
static Value fromJSON(JSContextRef ctx, const String& json) throw(JSException); static Value fromJSON(JSContextRef ctx, const String& json) throw(JSException);
static Value fromDynamic(JSContextRef ctx, folly::dynamic value) throw(JSException); static Value fromDynamic(JSContextRef ctx, folly::dynamic value) throw(JSException);
protected:
JSContextRef context() const; JSContextRef context() const;
protected:
JSContextRef m_context; JSContextRef m_context;
JSValueRef m_value; JSValueRef m_value;
}; };