Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(216)

Side by Side Diff: components/wug/generator/declaration.py

Issue 928163002: Initial implementation of WebUI generator (WUG) toolkit. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Owners updated. Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 import json
6 import os.path
7 import re
8 import util
9
10 DECLARATION_SCHEMA = (dict, {
11 'imports': (False, (list, unicode)),
12 'type': (True, unicode),
13 'children': (False, (list, (dict, {
14 'id': (True, unicode),
15 'type': (True, unicode)
16 }))),
17 'context': (False, (list, (dict, {
18 'name': (True, unicode),
19 'type': (False, unicode),
20 'default': (False, object)
21 }))),
22 'events': (False, (list, unicode)),
23 'strings': (False, (list, unicode))
24 })
25
26 # Returns (True,) if |obj| matches |schema|.
27 # Otherwise returns (False, msg), where |msg| is a diagnostic message.
28 def MatchSchema(obj, schema):
29 expected_type = schema[0] if isinstance(schema, tuple) else schema
30 if not isinstance(obj, expected_type):
31 return (False, 'Wrong type, expected %s, got %s.' %
32 (expected_type, type(obj)))
33 if expected_type == dict:
34 obj_keys = set(obj.iterkeys())
35 allowed_keys = set(schema[1].iterkeys())
36 required_keys = set(kv[0] for kv in schema[1].iteritems() if kv[1][0])
37 if not obj_keys.issuperset(required_keys):
38 missing_keys = required_keys.difference(obj_keys)
39 return (False, 'Missing required key%s %s.' %
40 ('s' if len(missing_keys) > 1 else '',
41 ', '.join('\'%s\'' % k for k in missing_keys)))
42 if not obj_keys.issubset(allowed_keys):
43 unknown_keys = obj_keys.difference(allowed_keys)
44 return (False, 'Unknown key%s %s.' %
45 ('s' if len(unknown_keys) > 1 else '',
46 ', '.join('\'%s\'' % k for k in unknown_keys)))
47 for key in obj:
48 match = MatchSchema(obj[key], schema[1][key][1])
49 if not match[0]:
50 return (False, ('[\'%s\'] ' % key) + match[1])
51 elif expected_type == list:
52 for i, item in enumerate(obj):
53 match = MatchSchema(item, schema[1])
54 if not match[0]:
55 return (False, ('[%d] ' % i) + match[1])
56 return (True,)
57
58 def CheckDeclarationIsValid(declaration):
59 match = MatchSchema(declaration, DECLARATION_SCHEMA)
60 if not match[0]:
61 raise Exception('Declaration is not valid: ' + match[1])
62
63
64 class FieldDeclaration(object):
65 ALLOWED_TYPES = [
66 'boolean',
67 'integer',
68 'double',
69 'string',
70 'string_list'
71 ]
72
73 DEFAULTS = {
74 'boolean': False,
75 'integer': 0,
76 'double': 0.0,
77 'string': u'',
78 'string_list': []
79 }
80
81 def __init__(self, declaration):
82 self.name = declaration['name']
83 self.id = util.ToLowerCamelCase(self.name)
84 self.type = declaration['type'] if 'type' in declaration else 'string'
85 if self.type not in self.ALLOWED_TYPES:
86 raise Exception('Unknown type of context field "%s": "%s"' %
87 (self.name, self.type))
88 self.default_value = declaration['default'] if 'default' in declaration \
89 else self.DEFAULTS[self.type]
90 if type(self.default_value) != type(self.DEFAULTS[self.type]):
91 raise Exception('Wrong type of default for field "%s": '
92 'expected "%s", got "%s"' %
93 (self.name,
94 type(self.DEFAULTS[self.type]),
95 type(self.default_value)))
96
97 class Declaration(object):
98 class DeclarationsStorage(object):
99 def __init__(self):
100 self.by_path = {}
101 self.by_type = {}
102
103 def Add(self, declaration):
104 assert declaration.path not in self.by_path
105 self.by_path[declaration.path] = declaration
106 if declaration.type in self.by_type:
107 raise Exception(
108 'Redefinition of "%s" in "%s". Previous definition was in "%s".' % \
109 (declaration.type, declaration.path,
110 self.by_type[declaration.type].path))
111 self.by_type[declaration.type] = declaration
112
113 def HasPath(self, path):
114 return path in self.by_path
115
116 def GetByPath(self, path):
117 return self.by_path[path]
118
119 def GetByType(self, type):
120 return self.by_type[type]
121
122 def GetKnownPathes(self):
123 return self.by_path.keys()
124
125
126 def __init__(self, path, known_declarations=None):
127 if known_declarations is None:
128 known_declarations = Declaration.DeclarationsStorage()
129 self.path = path
130 self.data = json.load(open(path, 'r'))
131 CheckDeclarationIsValid(self.data)
132 known_declarations.Add(self)
133 if 'imports' in self.data:
134 for import_path in self.data['imports']:
135 if not known_declarations.HasPath(import_path):
136 Declaration(import_path, known_declarations)
137 self.children = {}
138 if 'children' in self.data:
139 for child_data in self.data['children']:
140 self.children[child_data['id']] = \
141 known_declarations.GetByType(child_data['type'])
142 if 'strings' not in self.data:
143 self.data['strings'] = {}
144 if 'context' not in self.data:
145 self.data['context'] = []
146 if 'namespace' not in self.data:
147 self.data['namespace'] = 'gen'
148 if 'events' not in self.data:
149 self.data['events'] = []
150 self.fields = [FieldDeclaration(d) for d in self.data['context']]
151 fields_names = [field.name for field in self.fields]
152 if len(fields_names) > len(set(fields_names)):
153 raise Exception('Duplicate fields in declaration.')
154 self.known_declarations = known_declarations
155
156 @property
157 def type(self):
158 return self.data['type']
159
160 @property
161 def namespace(self):
162 return self.data['namespace']
163
164 @property
165 def strings(self):
166 return self.data['strings']
167
168 @property
169 def events(self):
170 return self.data['events']
171
172 @property
173 def webui_view_basename(self):
174 return self.type + '_web_ui_view'
175
176 @property
177 def webui_view_h_name(self):
178 return self.webui_view_basename + '.h'
179
180 @property
181 def webui_view_cc_name(self):
182 return self.webui_view_basename + '.cc'
183
184 @property
185 def webui_view_include_path(self):
186 return os.path.join(os.path.dirname(self.path), self.webui_view_h_name)
187
188 @property
189 def view_model_basename(self):
190 return self.type + '_view_model'
191
192 @property
193 def view_model_h_name(self):
194 return self.view_model_basename + '.h'
195
196 @property
197 def view_model_cc_name(self):
198 return self.view_model_basename + '.cc'
199
200 @property
201 def view_model_include_path(self):
202 return os.path.join(os.path.dirname(self.path), self.view_model_h_name)
203
204 @property
205 def html_view_basename(self):
206 return '%s-view' % self.type.replace('_', '-')
207
208 @property
209 def html_view_html_name(self):
210 return self.html_view_basename + '.html'
211
212 @property
213 def html_view_js_name(self):
214 return self.html_view_basename + '.js'
215
216 @property
217 def html_view_html_include_path(self):
218 return os.path.join(os.path.dirname(self.path), self.html_view_html_name)
219
220 @property
221 def html_view_js_include_path(self):
222 return os.path.join(os.path.dirname(self.path), self.html_view_js_name)
223
224 @property
225 def build_target(self):
226 return re.sub(r'[/.\\-]', '_', self.path)
227
228 @property
229 def webui_view_class(self):
230 return util.ToUpperCamelCase(self.type) + 'WebUIView'
231
232 @property
233 def view_model_class(self):
234 return util.ToUpperCamelCase(self.type) + 'ViewModel'
235
236 @property
237 def imports(self):
238 res = set(self.known_declarations.GetKnownPathes())
239 res.remove(self.path)
240 return res
241
242
243
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698