Index: extensions/renderer/api_binding.cc |
diff --git a/extensions/renderer/api_binding.cc b/extensions/renderer/api_binding.cc |
index 9856a8158e731a151d27875cb6721118f9eca6c9..b4b015c34f5a123fae149a2386ed32b02130b3fb 100644 |
--- a/extensions/renderer/api_binding.cc |
+++ b/extensions/renderer/api_binding.cc |
@@ -9,6 +9,7 @@ |
#include "base/bind.h" |
#include "base/logging.h" |
#include "base/memory/ptr_util.h" |
+#include "base/strings/string_util.h" |
#include "base/strings/stringprintf.h" |
#include "base/values.h" |
#include "extensions/common/extension_api.h" |
@@ -23,6 +24,31 @@ namespace extensions { |
namespace { |
+// Returns the name of the enum value for use in JavaScript; JS enum entries use |
+// SCREAMING_STYLE. |
+std::string GetJSEnumEntryName(const std::string& original) { |
+ std::string result; |
+ DCHECK(!original.empty()); |
+ // If the original starts with a digit, prefix it with an underscore. |
+ if (base::IsAsciiDigit(original[0])) |
+ result.push_back('_'); |
+ // Given 'myEnum-Foo': |
+ for (size_t i = 0; i < original.size(); ++i) { |
+ // Add an underscore between camelcased items: |
+ // 'myEnum-Foo' -> 'mY_Enum-Foo' |
+ if (i > 0 && base::IsAsciiLower(original[i - 1]) && |
+ base::IsAsciiUpper(original[i])) { |
+ result.push_back('_'); |
+ result.push_back(original[i]); |
+ } else if (original[i] == '-') { // 'mY_Enum-Foo' -> 'mY_Enum_Foo' |
+ result.push_back('_'); |
+ } else { // 'mY_Enum_Foo' -> 'MY_ENUM_FOO' |
+ result.push_back(base::ToUpperASCII(original[i])); |
+ } |
+ } |
+ return result; |
+} |
+ |
const char kExtensionAPIPerContextKey[] = "extension_api_binding"; |
struct APIPerContextData : public base::SupportsUserData::Data { |
@@ -88,6 +114,7 @@ APIBinding::APIBinding(const std::string& api_name, |
signatures_[name] = base::MakeUnique<APISignature>(*params); |
} |
} |
+ |
if (type_definitions) { |
for (const auto& type : *type_definitions) { |
const base::DictionaryValue* type_dict = nullptr; |
@@ -97,9 +124,25 @@ APIBinding::APIBinding(const std::string& api_name, |
DCHECK(type_refs->find(id) == type_refs->end()); |
// TODO(devlin): refs are sometimes preceeded by the API namespace; we |
// might need to take that into account. |
- (*type_refs)[id] = base::MakeUnique<ArgumentSpec>(*type_dict); |
+ auto argument_spec = base::MakeUnique<ArgumentSpec>(*type_dict); |
+ const std::set<std::string>& enum_values = argument_spec->enum_values(); |
+ if (!enum_values.empty()) { |
+ // Type names may be prefixed by the api name. If so, remove the prefix. |
+ base::Optional<std::string> stripped_id; |
+ if (base::StartsWith(id, api_name_, base::CompareCase::SENSITIVE)) |
+ stripped_id = id.substr(api_name_.size() + 1); // +1 for trailing '.' |
+ std::vector<EnumEntry>& entries = |
+ enums_[stripped_id ? *stripped_id : id]; |
+ entries.reserve(enum_values.size()); |
+ for (const auto& enum_value : enum_values) { |
+ entries.push_back( |
+ std::make_pair(enum_value, GetJSEnumEntryName(enum_value))); |
+ } |
+ } |
+ (*type_refs)[id] = std::move(argument_spec); |
} |
} |
+ |
if (event_definitions) { |
event_names_.reserve(event_definitions->GetSize()); |
for (const auto& event : *event_definitions) { |
@@ -134,6 +177,7 @@ v8::Local<v8::Object> APIBinding::CreateInstance( |
per_context_data->SetUserData(kExtensionAPIPerContextKey, |
api_data.release()); |
} |
+ |
for (const auto& sig : signatures_) { |
std::string full_method_name = |
base::StringPrintf("%s.%s", api_name_.c_str(), sig.first.c_str()); |
@@ -169,6 +213,22 @@ v8::Local<v8::Object> APIBinding::CreateInstance( |
DCHECK(success.FromJust()); |
} |
+ for (const auto& entry : enums_) { |
+ // TODO(devlin): Store these on an ObjectTemplate. |
+ v8::Local<v8::Object> enum_object = v8::Object::New(isolate); |
+ for (const auto& enum_entry : entry.second) { |
+ v8::Maybe<bool> success = enum_object->CreateDataProperty( |
+ context, gin::StringToSymbol(isolate, enum_entry.second), |
+ gin::StringToSymbol(isolate, enum_entry.first)); |
+ DCHECK(success.IsJust()); |
+ DCHECK(success.FromJust()); |
+ } |
+ v8::Maybe<bool> success = object->CreateDataProperty( |
+ context, gin::StringToSymbol(isolate, entry.first), enum_object); |
+ DCHECK(success.IsJust()); |
+ DCHECK(success.FromJust()); |
+ } |
+ |
binding_hooks_->InitializeInContext(context, api_name_); |
return object; |