1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/common/api/declarative/declarative_manifest_data.h"
7 #include "base/strings/stringprintf.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "extensions/common/manifest_constants.h"
11 using base::UTF8ToUTF16
;
12 using base::StringPrintf
;
14 namespace extensions
{
18 const char* ValueTypeToString(const base::Value
* value
) {
19 const base::Value::Type type
= value
->GetType();
20 static const char* strings
[] = {"null",
28 CHECK(static_cast<size_t>(type
) < arraysize(strings
));
34 explicit ErrorBuilder(base::string16
* error
) : error_(error
) {}
36 // Appends a literal string |error|.
37 void Append(const char* error
) {
39 error_
->append(UTF8ToUTF16("; "));
40 error_
->append(UTF8ToUTF16(error
));
43 // Appends a string |error| with the first %s replaced by |sub|.
44 void Append(const char* error
, const char* sub
) {
45 Append(base::StringPrintf(error
, sub
).c_str());
49 base::string16
* error_
;
50 DISALLOW_COPY_AND_ASSIGN(ErrorBuilder
);
53 // Converts a rule defined in the manifest into a JSON internal format. The
54 // difference is that actions and conditions use a "type" key to define the
55 // type of rule/condition, while the internal format uses a "instanceType" key
56 // for this. This function walks through all the conditions and rules to swap
57 // the manifest key for the internal key.
58 bool ConvertManifestRule(const linked_ptr
<DeclarativeManifestData::Rule
>& rule
,
59 ErrorBuilder
* error_builder
) {
61 [error_builder
](std::vector
<linked_ptr
<base::Value
>>& list
) {
62 for (const linked_ptr
<base::Value
>& value
: list
) {
63 base::DictionaryValue
* dictionary
= nullptr;
64 if (!value
->GetAsDictionary(&dictionary
)) {
65 error_builder
->Append("expected dictionary, got %s",
66 ValueTypeToString(value
.get()));
70 if (!dictionary
->GetString("type", &type
)) {
71 error_builder
->Append("'type' is required and must be a string");
74 dictionary
->Remove("type", nullptr);
75 dictionary
->SetString("instanceType", type
);
79 return convert_list(rule
->actions
) && convert_list(rule
->conditions
);
84 DeclarativeManifestData::DeclarativeManifestData() {
87 DeclarativeManifestData::~DeclarativeManifestData() {
91 DeclarativeManifestData
* DeclarativeManifestData::Get(
92 const Extension
* extension
) {
93 return static_cast<DeclarativeManifestData
*>(
94 extension
->GetManifestData(manifest_keys::kEventRules
));
98 scoped_ptr
<DeclarativeManifestData
> DeclarativeManifestData::FromValue(
99 const base::Value
& value
,
100 base::string16
* error
) {
101 // The following is an example of how an event programmatic rule definition
102 // translates to a manifest definition.
106 // chrome.declarativeContent.onPageChanged.addRules([{
108 // new chrome.declarativeContent.ShowPageAction()
111 // new chrome.declarativeContent.PageStateMatcher({css: ["video"]})
118 // "event" : "declarativeContent.onPageChanged",
120 // "type": "declarativeContent.ShowPageAction"
124 // "type" : "declarativeContent.PageStateMatcher"
128 // The javascript objects get translated into JSON objects with a "type"
129 // field to indicate the instance type. Instead of adding rules to a
130 // specific event list, each rule has an "event" field to indicate which
131 // event it applies to.
133 ErrorBuilder
error_builder(error
);
134 scoped_ptr
<DeclarativeManifestData
> result(new DeclarativeManifestData());
135 const base::ListValue
* list
= nullptr;
136 if (!value
.GetAsList(&list
)) {
137 error_builder
.Append("'event_rules' expected list, got %s",
138 ValueTypeToString(&value
));
139 return scoped_ptr
<DeclarativeManifestData
>();
142 for (size_t i
= 0; i
< list
->GetSize(); ++i
) {
143 const base::DictionaryValue
* dict
= nullptr;
144 if (!list
->GetDictionary(i
, &dict
)) {
145 const base::Value
* value
= nullptr;
146 if (list
->Get(i
, &value
))
147 error_builder
.Append("expected dictionary, got %s",
148 ValueTypeToString(value
));
150 error_builder
.Append("expected dictionary");
151 return scoped_ptr
<DeclarativeManifestData
>();
154 if (!dict
->GetString("event", &event
)) {
155 error_builder
.Append("'event' is required");
156 return scoped_ptr
<DeclarativeManifestData
>();
159 linked_ptr
<Rule
> rule(new Rule());
160 if (!Rule::Populate(*dict
, rule
.get())) {
161 error_builder
.Append("rule failed to populate");
162 return scoped_ptr
<DeclarativeManifestData
>();
165 if (!ConvertManifestRule(rule
, &error_builder
))
166 return scoped_ptr
<DeclarativeManifestData
>();
168 result
->event_rules_map_
[event
].push_back(rule
);
170 return result
.Pass();
173 std::vector
<linked_ptr
<DeclarativeManifestData::Rule
>>&
174 DeclarativeManifestData::RulesForEvent(const std::string
& event
) {
175 return event_rules_map_
[event
];
178 } // namespace extensions