Chromium Code Reviews| Index: extensions/common/api/declarative/declarative_manifest_data.cc |
| diff --git a/extensions/common/api/declarative/declarative_manifest_data.cc b/extensions/common/api/declarative/declarative_manifest_data.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..a5a3de2317083be44cf6c88d56ad81bf9317c919 |
| --- /dev/null |
| +++ b/extensions/common/api/declarative/declarative_manifest_data.cc |
| @@ -0,0 +1,176 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "extensions/common/api/declarative/declarative_manifest_data.h" |
| + |
| +#include "base/strings/stringprintf.h" |
| +#include "base/strings/utf_string_conversions.h" |
| +#include "extensions/common/manifest_constants.h" |
| + |
| +using base::UTF8ToUTF16; |
| +using base::StringPrintf; |
| + |
| +namespace extensions { |
| + |
| +namespace { |
| + |
| +const char* ValueTypeToString(const base::Value* value) { |
| + const base::Value::Type type = value->GetType(); |
| + static const char* strings[] = {"null", |
| + "boolean", |
| + "integer", |
| + "double", |
| + "string", |
| + "binary", |
| + "dictionary", |
| + "list"}; |
| + CHECK(static_cast<size_t>(type) < arraysize(strings)); |
| + return strings[type]; |
| +} |
| + |
| +class ErrorBuilder { |
| + public: |
| + ErrorBuilder(base::string16* error) : error_(error) {} |
|
not at google - send to devlin
2015/06/09 20:55:41
explicit
danduong
2015/06/10 00:17:16
Done.
|
| + |
| + // Appends a literal string |error|. |
| + void Append(const char* error) { |
| + if (error_->length()) |
| + error_->append(UTF8ToUTF16("; ")); |
| + error_->append(UTF8ToUTF16(error)); |
| + } |
| + |
| + // Appends a string |error| with the first %s replaced by |sub|. |
| + void Append(const char* error, const char* sub) { |
| + Append(base::StringPrintf(error, sub).c_str()); |
| + } |
| + |
| + private: |
| + base::string16* error_; |
| + DISALLOW_COPY_AND_ASSIGN(ErrorBuilder); |
| +}; |
| + |
| +// Converts a rule defined in the manifest into a JSON internal format. The |
| +// difference is that actions and conditions use a "type" key to define the |
| +// type of rule/condition, while the internal format uses a "instanceType" key |
| +// for this. This function walks through all the conditions and rules to swap |
| +// the manifest key for the internal key. |
| +bool ConvertManifestRule(const linked_ptr<DeclarativeManifestData::Rule>& rule, |
| + ErrorBuilder* error_builder) { |
| + auto convert_list = |
| + [error_builder](std::vector<linked_ptr<base::Value>>& list) { |
| + for (const linked_ptr<base::Value>& value : list) { |
| + base::DictionaryValue* dictionary = nullptr; |
| + if (!value->GetAsDictionary(&dictionary)) { |
| + error_builder->Append("expected dictionary, got %s", |
| + ValueTypeToString(value.get())); |
| + return false; |
| + } |
| + std::string type; |
| + if (!dictionary->GetString("type", &type)) { |
| + error_builder->Append("'type' is required"); |
|
not at google - send to devlin
2015/06/09 20:55:40
this will also fail if "type" is set but isn't a s
danduong
2015/06/10 00:17:16
Done.
|
| + return false; |
| + } |
| + dictionary->Remove("type", nullptr); |
| + dictionary->SetString("instanceType", type); |
| + } |
| + return true; |
| + }; |
| + return convert_list(rule->actions) && convert_list(rule->conditions); |
| +} |
| + |
| +} // namespace |
| + |
| +DeclarativeManifestData::DeclarativeManifestData() { |
| +} |
| + |
| +DeclarativeManifestData::~DeclarativeManifestData() { |
| +} |
| + |
| +// static |
| +DeclarativeManifestData* DeclarativeManifestData::Get( |
| + const Extension* extension) { |
| + return static_cast<DeclarativeManifestData*>( |
| + extension->GetManifestData(manifest_keys::kEventRules)); |
| +} |
| + |
| +// static |
| +scoped_ptr<DeclarativeManifestData> DeclarativeManifestData::FromValue( |
| + const base::Value& value, |
| + base::string16* error) { |
| + // The following is an example of how an event programmatic rule definition |
| + // translates to a manifest definition. |
| + // |
| + // From javascript: |
| + // |
| + // chrome.declarativeContent.onPageChanged.addRules([{ |
| + // actions: [ |
| + // new chrome.declarativeContent.ShowPageAction() |
| + // ], |
| + // conditions: [ |
| + // new chrome.declarativeContent.PageStateMatcher({css: ["video"]}) |
| + // ] |
| + // }]); |
| + // |
| + // In manifest: |
| + // |
| + // "event_rules": [{ |
| + // "event" : "declarativeContent.onPageChanged", |
| + // "actions" : [{ |
| + // "type": "declarativeContent.ShowPageAction" |
| + // }], |
| + // "conditions" : [{ |
| + // "css": ["video"], |
| + // "type" : "declarativeContent.PageStateMatcher" |
| + // }] |
| + // }] |
| + // |
| + // The javascript objects get translated into JSON objects with a "type" |
| + // field to indicate the instance type. Instead of adding rules to a |
| + // specific event list, each rule has an "event" field to indicate which |
| + // event it applies to. |
| + // |
| + ErrorBuilder error_builder(error); |
| + scoped_ptr<DeclarativeManifestData> result(new DeclarativeManifestData()); |
| + const base::ListValue* list = nullptr; |
| + if (!value.GetAsList(&list)) { |
| + error_builder.Append("'event_rules' expected list, got %s", |
| + ValueTypeToString(&value)); |
| + return scoped_ptr<DeclarativeManifestData>(); |
| + } |
| + |
| + for (size_t i = 0; i < list->GetSize(); ++i) { |
| + const base::DictionaryValue* dict = nullptr; |
| + if (!list->GetDictionary(i, &dict)) { |
| + const base::Value* value = nullptr; |
| + if (list->Get(i, &value)) |
| + error_builder.Append("expected dictionary, got %s", |
| + ValueTypeToString(value)); |
| + else |
| + error_builder.Append("expected dictionary"); |
| + return scoped_ptr<DeclarativeManifestData>(); |
| + } |
| + std::string event; |
| + if (!dict->GetString("event", &event)) { |
| + error_builder.Append("'event' is required"); |
| + return scoped_ptr<DeclarativeManifestData>(); |
| + } |
| + |
| + linked_ptr<Rule> rule(new Rule()); |
| + if (Rule::Populate(*dict, rule.get()) && |
| + ConvertManifestRule(rule, &error_builder)) { |
| + result->event_rules_map_[event].push_back(rule); |
| + } else { |
| + error_builder.Append("rule failed to populate"); |
|
not at google - send to devlin
2015/06/09 20:55:40
I think that, now, the Populate and the ConvertMan
|
| + return scoped_ptr<DeclarativeManifestData>(); |
| + } |
| + } |
| + return result.Pass(); |
| +} |
| + |
| +std::vector<linked_ptr<DeclarativeManifestData::Rule>>& |
| +DeclarativeManifestData::RulesForEvent(const std::string& event) { |
| + return event_rules_map_[event]; |
| +} |
| + |
| +} // namespace extensions |