blob: 16530e7f465b2e523958c8e00afdc8c1e6f652d1 [file] [log] [blame]
[email protected]15f08dd2012-01-27 07:29:481# Copyright (c) 2012 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
5import os.path
6
[email protected]b2fad3f2012-11-20 02:13:247from json_parse import OrderedDict
[email protected]cb5670c2013-04-10 06:31:088from memoize import memoize
[email protected]b2fad3f2012-11-20 02:13:249
[email protected]0853bcf2013-11-06 05:14:3310
[email protected]116f0a3a2012-04-19 04:22:3811class ParseException(Exception):
12 """Thrown when data in the model is invalid.
13 """
14 def __init__(self, parent, message):
15 hierarchy = _GetModelHierarchy(parent)
16 hierarchy.append(message)
17 Exception.__init__(
18 self, 'Model parse exception at:\n' + '\n'.join(hierarchy))
19
[email protected]0853bcf2013-11-06 05:14:3320
[email protected]15f08dd2012-01-27 07:29:4821class Model(object):
22 """Model of all namespaces that comprise an API.
[email protected]cfe484902012-02-15 14:52:3223
24 Properties:
25 - |namespaces| a map of a namespace name to its model.Namespace
[email protected]15f08dd2012-01-27 07:29:4826 """
27 def __init__(self):
28 self.namespaces = {}
29
lfg8a1bee32014-08-29 03:56:2830 def AddNamespace(self,
31 json,
32 source_file,
33 include_compiler_options=False,
34 environment=None):
[email protected]a1f774972012-04-17 02:11:0935 """Add a namespace's json to the model and returns the namespace.
[email protected]15f08dd2012-01-27 07:29:4836 """
[email protected]4636c832013-01-11 02:10:1137 namespace = Namespace(json,
38 source_file,
lfg8a1bee32014-08-29 03:56:2839 include_compiler_options=include_compiler_options,
40 environment=environment)
[email protected]15f08dd2012-01-27 07:29:4841 self.namespaces[namespace.name] = namespace
42 return namespace
43
[email protected]0853bcf2013-11-06 05:14:3344
45def CreateFeature(name, model):
46 if isinstance(model, dict):
47 return SimpleFeature(name, model)
48 return ComplexFeature(name, [SimpleFeature(name, child) for child in model])
49
50
51class ComplexFeature(object):
52 """A complex feature which may be made of several simple features.
53
54 Properties:
55 - |name| the name of the feature
56 - |unix_name| the unix_name of the feature
57 - |feature_list| a list of simple features which make up the feature
58 """
59 def __init__(self, feature_name, features):
60 self.name = feature_name
61 self.unix_name = UnixName(self.name)
62 self.feature_list = features
63
64class SimpleFeature(object):
65 """A simple feature, which can make up a complex feature, as specified in
66 files such as chrome/common/extensions/api/_permission_features.json.
67
68 Properties:
69 - |name| the name of the feature
70 - |unix_name| the unix_name of the feature
71 - |channel| the channel where the feature is released
72 - |extension_types| the types which can use the feature
73 - |whitelist| a list of extensions allowed to use the feature
74 """
75 def __init__(self, feature_name, feature_def):
76 self.name = feature_name
77 self.unix_name = UnixName(self.name)
78 self.channel = feature_def['channel']
79 self.extension_types = feature_def['extension_types']
80 self.whitelist = feature_def.get('whitelist')
81
82
[email protected]15f08dd2012-01-27 07:29:4883class Namespace(object):
84 """An API namespace.
[email protected]cfe484902012-02-15 14:52:3285
86 Properties:
87 - |name| the name of the namespace
[email protected]8426f8d72013-06-23 04:24:5588 - |description| the description of the namespace
[email protected]29163bc2014-01-27 21:50:5989 - |deprecated| a reason and possible alternative for a deprecated api
[email protected]712eca0f2012-02-21 01:13:0790 - |unix_name| the unix_name of the namespace
91 - |source_file| the file that contained the namespace definition
92 - |source_file_dir| the directory component of |source_file|
93 - |source_file_filename| the filename component of |source_file|
[email protected]4636c832013-01-11 02:10:1194 - |platforms| if not None, the list of platforms that the namespace is
95 available to
[email protected]cfe484902012-02-15 14:52:3296 - |types| a map of type names to their model.Type
97 - |functions| a map of function names to their model.Function
[email protected]b741e8f2012-07-16 21:47:2498 - |events| a map of event names to their model.Function
[email protected]116f0a3a2012-04-19 04:22:3899 - |properties| a map of property names to their model.Property
[email protected]bee7a7932013-08-12 23:45:38100 - |compiler_options| the compiler_options dict, only not empty if
[email protected]4636c832013-01-11 02:10:11101 |include_compiler_options| is True
[email protected]15f08dd2012-01-27 07:29:48102 """
lfg8a1bee32014-08-29 03:56:28103 def __init__(self,
104 json,
105 source_file,
106 include_compiler_options=False,
107 environment=None):
[email protected]15f08dd2012-01-27 07:29:48108 self.name = json['namespace']
[email protected]8426f8d72013-06-23 04:24:55109 if 'description' not in json:
[email protected]a081aeb2013-07-09 20:52:47110 # TODO(kalman): Go back to throwing an error here.
111 print('%s must have a "description" field. This will appear '
[email protected]8426f8d72013-06-23 04:24:55112 'on the API summary page.' % self.name)
[email protected]a081aeb2013-07-09 20:52:47113 json['description'] = ''
114 self.description = json['description']
[email protected]29163bc2014-01-27 21:50:59115 self.deprecated = json.get('deprecated', None)
[email protected]4ba6bdc2012-06-18 20:40:14116 self.unix_name = UnixName(self.name)
[email protected]15f08dd2012-01-27 07:29:48117 self.source_file = source_file
118 self.source_file_dir, self.source_file_filename = os.path.split(source_file)
[email protected]70e263e2014-02-09 10:45:09119 self.short_filename = os.path.basename(source_file).split('.')[0]
[email protected]feba21e2012-03-02 15:05:27120 self.parent = None
[email protected]4636c832013-01-11 02:10:11121 self.platforms = _GetPlatforms(json)
[email protected]242d5e7a2013-01-17 06:50:31122 toplevel_origin = Origin(from_client=True, from_json=True)
123 self.types = _GetTypes(self, json, self, toplevel_origin)
124 self.functions = _GetFunctions(self, json, self)
125 self.events = _GetEvents(self, json, self)
126 self.properties = _GetProperties(self, json, self, toplevel_origin)
[email protected]03e5ffe2013-11-07 01:54:53127 if include_compiler_options:
128 self.compiler_options = json.get('compiler_options', {})
129 else:
130 self.compiler_options = {}
lfg8a1bee32014-08-29 03:56:28131 self.environment = environment
[email protected]0b022482013-10-03 19:38:05132 self.documentation_options = json.get('documentation_options', {})
[email protected]15f08dd2012-01-27 07:29:48133
[email protected]0853bcf2013-11-06 05:14:33134
[email protected]242d5e7a2013-01-17 06:50:31135class Origin(object):
136 """Stores the possible origin of model object as a pair of bools. These are:
137
138 |from_client| indicating that instances can originate from users of
139 generated code (for example, function results), or
140 |from_json| indicating that instances can originate from the JSON (for
141 example, function parameters)
142
143 It is possible for model objects to originate from both the client and json,
144 for example Types defined in the top-level schema, in which case both
145 |from_client| and |from_json| would be True.
146 """
147 def __init__(self, from_client=False, from_json=False):
148 if not from_client and not from_json:
149 raise ValueError('One of from_client or from_json must be true')
150 self.from_client = from_client
151 self.from_json = from_json
152
[email protected]0853bcf2013-11-06 05:14:33153
[email protected]15f08dd2012-01-27 07:29:48154class Type(object):
155 """A Type defined in the json.
[email protected]cfe484902012-02-15 14:52:32156
157 Properties:
158 - |name| the type name
[email protected]242d5e7a2013-01-17 06:50:31159 - |namespace| the Type's namespace
[email protected]cfe484902012-02-15 14:52:32160 - |description| the description of the type (if provided)
[email protected]feba21e2012-03-02 15:05:27161 - |properties| a map of property unix_names to their model.Property
162 - |functions| a map of function names to their model.Function
[email protected]d32b8e52012-07-23 18:40:08163 - |events| a map of event names to their model.Event
[email protected]242d5e7a2013-01-17 06:50:31164 - |origin| the Origin of the type
165 - |property_type| the PropertyType of this Type
[email protected]cf6d0b32012-04-12 04:30:22166 - |item_type| if this is an array, the type of items in the array
[email protected]0b255f002012-10-05 01:58:47167 - |simple_name| the name of this Type without a namespace
[email protected]242d5e7a2013-01-17 06:50:31168 - |additional_properties| the type of the additional properties, if any is
169 specified
[email protected]15f08dd2012-01-27 07:29:48170 """
[email protected]242d5e7a2013-01-17 06:50:31171 def __init__(self,
172 parent,
173 name,
174 json,
175 namespace,
176 origin):
177 self.name = name
178 self.namespace = namespace
179 self.simple_name = _StripNamespace(self.name, namespace)
180 self.unix_name = UnixName(self.name)
181 self.description = json.get('description', None)
182 self.origin = origin
183 self.parent = parent
184 self.instance_of = json.get('isInstanceOf', None)
185
186 # TODO(kalman): Only objects need functions/events/properties, but callers
187 # assume that all types have them. Fix this.
188 self.functions = _GetFunctions(self, json, namespace)
189 self.events = _GetEvents(self, json, namespace)
190 self.properties = _GetProperties(self, json, namespace, origin)
191
192 json_type = json.get('type', None)
193 if json_type == 'array':
194 self.property_type = PropertyType.ARRAY
195 self.item_type = Type(
196 self, '%sType' % name, json['items'], namespace, origin)
197 elif '$ref' in json:
198 self.property_type = PropertyType.REF
199 self.ref_type = json['$ref']
200 elif 'enum' in json and json_type == 'string':
201 self.property_type = PropertyType.ENUM
[email protected]7f138d42013-11-01 05:27:27202 self.enum_values = [EnumValue(value) for value in json['enum']]
[email protected]fad5da262014-05-15 08:04:00203 self.cpp_enum_prefix_override = json.get('cpp_enum_prefix_override', None)
[email protected]242d5e7a2013-01-17 06:50:31204 elif json_type == 'any':
205 self.property_type = PropertyType.ANY
206 elif json_type == 'binary':
207 self.property_type = PropertyType.BINARY
208 elif json_type == 'boolean':
209 self.property_type = PropertyType.BOOLEAN
210 elif json_type == 'integer':
211 self.property_type = PropertyType.INTEGER
212 elif (json_type == 'double' or
213 json_type == 'number'):
214 self.property_type = PropertyType.DOUBLE
215 elif json_type == 'string':
216 self.property_type = PropertyType.STRING
217 elif 'choices' in json:
218 self.property_type = PropertyType.CHOICES
[email protected]e11b9aa2013-07-13 00:05:42219 def generate_type_name(type_json):
220 if 'items' in type_json:
221 return '%ss' % generate_type_name(type_json['items'])
222 if '$ref' in type_json:
223 return type_json['$ref']
224 if 'type' in type_json:
225 return type_json['type']
226 return None
227 self.choices = [
228 Type(self,
229 generate_type_name(choice) or 'choice%s' % i,
230 choice,
231 namespace,
232 origin)
233 for i, choice in enumerate(json['choices'])]
[email protected]242d5e7a2013-01-17 06:50:31234 elif json_type == 'object':
[email protected]cf6d0b32012-04-12 04:30:22235 if not (
[email protected]117afcf2013-08-30 02:38:09236 'isInstanceOf' in json or
[email protected]cf6d0b32012-04-12 04:30:22237 'properties' in json or
238 'additionalProperties' in json or
[email protected]e975d112012-07-31 22:12:43239 'functions' in json or
240 'events' in json):
[email protected]116f0a3a2012-04-19 04:22:38241 raise ParseException(self, name + " has no properties or functions")
[email protected]242d5e7a2013-01-17 06:50:31242 self.property_type = PropertyType.OBJECT
243 additional_properties_json = json.get('additionalProperties', None)
244 if additional_properties_json is not None:
245 self.additional_properties = Type(self,
246 'additionalProperties',
247 additional_properties_json,
248 namespace,
249 origin)
250 else:
251 self.additional_properties = None
252 elif json_type == 'function':
253 self.property_type = PropertyType.FUNCTION
254 # Sometimes we might have an unnamed function, e.g. if it's a property
255 # of an object. Use the name of the property in that case.
256 function_name = json.get('name', name)
257 self.function = Function(self, function_name, json, namespace, origin)
258 else:
259 raise ParseException(self, 'Unsupported JSON type %s' % json_type)
[email protected]15f08dd2012-01-27 07:29:48260
[email protected]0853bcf2013-11-06 05:14:33261
[email protected]15f08dd2012-01-27 07:29:48262class Function(object):
263 """A Function defined in the API.
[email protected]cfe484902012-02-15 14:52:32264
265 Properties:
266 - |name| the function name
[email protected]4636c832013-01-11 02:10:11267 - |platforms| if not None, the list of platforms that the function is
268 available to
[email protected]cfe484902012-02-15 14:52:32269 - |params| a list of parameters to the function (order matters). A separate
[email protected]4636c832013-01-11 02:10:11270 parameter is used for each choice of a 'choices' parameter
[email protected]9c7830ba2013-10-17 19:28:46271 - |deprecated| a reason and possible alternative for a deprecated function
[email protected]cfe484902012-02-15 14:52:32272 - |description| a description of the function (if provided)
273 - |callback| the callback parameter to the function. There should be exactly
[email protected]4636c832013-01-11 02:10:11274 one
[email protected]4b3f7852012-07-17 06:33:30275 - |optional| whether the Function is "optional"; this only makes sense to be
[email protected]4636c832013-01-11 02:10:11276 present when the Function is representing a callback property
[email protected]0b255f002012-10-05 01:58:47277 - |simple_name| the name of this Function without a namespace
[email protected]32096af2013-02-06 01:29:31278 - |returns| the return type of the function; None if the function does not
279 return a value
[email protected]15f08dd2012-01-27 07:29:48280 """
[email protected]0b255f002012-10-05 01:58:47281 def __init__(self,
282 parent,
[email protected]242d5e7a2013-01-17 06:50:31283 name,
[email protected]0b255f002012-10-05 01:58:47284 json,
285 namespace,
[email protected]242d5e7a2013-01-17 06:50:31286 origin):
287 self.name = name
[email protected]0b255f002012-10-05 01:58:47288 self.simple_name = _StripNamespace(self.name, namespace)
[email protected]4636c832013-01-11 02:10:11289 self.platforms = _GetPlatforms(json)
[email protected]15f08dd2012-01-27 07:29:48290 self.params = []
[email protected]feba21e2012-03-02 15:05:27291 self.description = json.get('description')
[email protected]9c7830ba2013-10-17 19:28:46292 self.deprecated = json.get('deprecated')
[email protected]15f08dd2012-01-27 07:29:48293 self.callback = None
[email protected]4b3f7852012-07-17 06:33:30294 self.optional = json.get('optional', False)
[email protected]feba21e2012-03-02 15:05:27295 self.parent = parent
[email protected]a9ead752012-05-24 02:08:45296 self.nocompile = json.get('nocompile')
[email protected]c0718352012-08-21 02:34:24297 options = json.get('options', {})
298 self.conditions = options.get('conditions', [])
299 self.actions = options.get('actions', [])
300 self.supports_listeners = options.get('supportsListeners', True)
301 self.supports_rules = options.get('supportsRules', False)
[email protected]c18d6712013-10-03 18:39:30302 self.supports_dom = options.get('supportsDom', False)
[email protected]242d5e7a2013-01-17 06:50:31303
[email protected]c0718352012-08-21 02:34:24304 def GeneratePropertyFromParam(p):
[email protected]627b54d2013-02-04 23:53:59305 return Property(self, p['name'], p, namespace, origin)
[email protected]db943992012-08-02 14:02:54306
[email protected]c0718352012-08-21 02:34:24307 self.filters = [GeneratePropertyFromParam(filter)
308 for filter in json.get('filters', [])]
[email protected]db943992012-08-02 14:02:54309 callback_param = None
[email protected]b741e8f2012-07-16 21:47:24310 for param in json.get('parameters', []):
[email protected]15f08dd2012-01-27 07:29:48311 if param.get('type') == 'function':
[email protected]db943992012-08-02 14:02:54312 if callback_param:
313 # No ParseException because the webstore has this.
314 # Instead, pretend all intermediate callbacks are properties.
315 self.params.append(GeneratePropertyFromParam(callback_param))
316 callback_param = param
[email protected]15f08dd2012-01-27 07:29:48317 else:
[email protected]db943992012-08-02 14:02:54318 self.params.append(GeneratePropertyFromParam(param))
319
320 if callback_param:
[email protected]0b255f002012-10-05 01:58:47321 self.callback = Function(self,
[email protected]242d5e7a2013-01-17 06:50:31322 callback_param['name'],
[email protected]0b255f002012-10-05 01:58:47323 callback_param,
324 namespace,
[email protected]242d5e7a2013-01-17 06:50:31325 Origin(from_client=True))
[email protected]db943992012-08-02 14:02:54326
[email protected]491e60d32012-07-20 01:03:13327 self.returns = None
328 if 'returns' in json:
[email protected]627b54d2013-02-04 23:53:59329 self.returns = Type(self,
330 '%sReturnType' % name,
331 json['returns'],
332 namespace,
333 origin)
[email protected]15f08dd2012-01-27 07:29:48334
[email protected]0853bcf2013-11-06 05:14:33335
[email protected]15f08dd2012-01-27 07:29:48336class Property(object):
337 """A property of a type OR a parameter to a function.
[email protected]cfe484902012-02-15 14:52:32338 Properties:
339 - |name| name of the property as in the json. This shouldn't change since
340 it is the key used to access DictionaryValues
341 - |unix_name| the unix_style_name of the property. Used as variable name
342 - |optional| a boolean representing whether the property is optional
343 - |description| a description of the property (if provided)
[email protected]242d5e7a2013-01-17 06:50:31344 - |type_| the model.Type of this property
[email protected]0b255f002012-10-05 01:58:47345 - |simple_name| the name of this Property without a namespace
[email protected]04afd692013-11-14 19:35:04346 - |deprecated| a reason and possible alternative for a deprecated property
[email protected]15f08dd2012-01-27 07:29:48347 """
[email protected]627b54d2013-02-04 23:53:59348 def __init__(self, parent, name, json, namespace, origin):
[email protected]242d5e7a2013-01-17 06:50:31349 """Creates a Property from JSON.
350 """
[email protected]627b54d2013-02-04 23:53:59351 self.parent = parent
352 self.name = name
353 self._unix_name = UnixName(self.name)
354 self._unix_name_used = False
355 self.origin = origin
356 self.simple_name = _StripNamespace(self.name, namespace)
357 self.description = json.get('description', None)
358 self.optional = json.get('optional', None)
359 self.instance_of = json.get('isInstanceOf', None)
[email protected]04afd692013-11-14 19:35:04360 self.deprecated = json.get('deprecated')
[email protected]242d5e7a2013-01-17 06:50:31361
362 # HACK: only support very specific value types.
363 is_allowed_value = (
364 '$ref' not in json and
365 ('type' not in json or json['type'] == 'integer'
366 or json['type'] == 'string'))
367
[email protected]627b54d2013-02-04 23:53:59368 self.value = None
[email protected]242d5e7a2013-01-17 06:50:31369 if 'value' in json and is_allowed_value:
[email protected]627b54d2013-02-04 23:53:59370 self.value = json['value']
[email protected]242d5e7a2013-01-17 06:50:31371 if 'type' not in json:
372 # Sometimes the type of the value is left out, and we need to figure
373 # it out for ourselves.
[email protected]627b54d2013-02-04 23:53:59374 if isinstance(self.value, int):
[email protected]242d5e7a2013-01-17 06:50:31375 json['type'] = 'integer'
[email protected]627b54d2013-02-04 23:53:59376 elif isinstance(self.value, basestring):
[email protected]242d5e7a2013-01-17 06:50:31377 json['type'] = 'string'
378 else:
379 # TODO(kalman): support more types as necessary.
380 raise ParseException(
[email protected]627b54d2013-02-04 23:53:59381 parent,
382 '"%s" is not a supported type for "value"' % type(self.value))
[email protected]242d5e7a2013-01-17 06:50:31383
[email protected]627b54d2013-02-04 23:53:59384 self.type_ = Type(parent, name, json, namespace, origin)
[email protected]cfe484902012-02-15 14:52:32385
386 def GetUnixName(self):
387 """Gets the property's unix_name. Raises AttributeError if not set.
388 """
[email protected]116f0a3a2012-04-19 04:22:38389 if not self._unix_name:
[email protected]cfe484902012-02-15 14:52:32390 raise AttributeError('No unix_name set on %s' % self.name)
391 self._unix_name_used = True
392 return self._unix_name
393
394 def SetUnixName(self, unix_name):
395 """Set the property's unix_name. Raises AttributeError if the unix_name has
396 already been used (GetUnixName has been called).
397 """
398 if unix_name == self._unix_name:
399 return
400 if self._unix_name_used:
401 raise AttributeError(
402 'Cannot set the unix_name on %s; '
403 'it is already used elsewhere as %s' %
404 (self.name, self._unix_name))
405 self._unix_name = unix_name
406
407 unix_name = property(GetUnixName, SetUnixName)
[email protected]15f08dd2012-01-27 07:29:48408
[email protected]7f138d42013-11-01 05:27:27409class EnumValue(object):
410 """A single value from an enum.
411 Properties:
412 - |name| name of the property as in the json.
413 - |description| a description of the property (if provided)
414 """
415 def __init__(self, json):
416 if isinstance(json, dict):
417 self.name = json['name']
418 self.description = json.get('description')
419 else:
420 self.name = json
421 self.description = None
422
[email protected]fad5da262014-05-15 08:04:00423 def CamelName(self):
424 return CamelName(self.name)
425
[email protected]4636c832013-01-11 02:10:11426class _Enum(object):
427 """Superclass for enum types with a "name" field, setting up repr/eq/ne.
428 Enums need to do this so that equality/non-equality work over pickling.
[email protected]fe027682012-08-21 01:51:34429 """
[email protected]4636c832013-01-11 02:10:11430 @staticmethod
431 def GetAll(cls):
432 """Yields all _Enum objects declared in |cls|.
433 """
434 for prop_key in dir(cls):
435 prop_value = getattr(cls, prop_key)
436 if isinstance(prop_value, _Enum):
437 yield prop_value
438
439 def __init__(self, name):
[email protected]fe027682012-08-21 01:51:34440 self.name = name
441
[email protected]dc5f2fecf2012-08-31 01:55:51442 def __eq__(self, other):
[email protected]4636c832013-01-11 02:10:11443 return type(other) == type(self) and other.name == self.name
[email protected]e15dccb2012-10-05 06:02:25444 def __ne__(self, other):
[email protected]e15dccb2012-10-05 06:02:25445 return not (self == other)
446
[email protected]e11b9aa2013-07-13 00:05:42447 def __repr__(self):
448 return self.name
449
450 def __str__(self):
451 return repr(self)
452
[email protected]0853bcf2013-11-06 05:14:33453
[email protected]4636c832013-01-11 02:10:11454class _PropertyTypeInfo(_Enum):
455 def __init__(self, is_fundamental, name):
456 _Enum.__init__(self, name)
457 self.is_fundamental = is_fundamental
458
[email protected]0853bcf2013-11-06 05:14:33459
[email protected]15f08dd2012-01-27 07:29:48460class PropertyType(object):
461 """Enum of different types of properties/parameters.
462 """
[email protected]242d5e7a2013-01-17 06:50:31463 ANY = _PropertyTypeInfo(False, "any")
[email protected]e11b9aa2013-07-13 00:05:42464 ARRAY = _PropertyTypeInfo(False, "array")
465 BINARY = _PropertyTypeInfo(False, "binary")
466 BOOLEAN = _PropertyTypeInfo(True, "boolean")
467 CHOICES = _PropertyTypeInfo(False, "choices")
468 DOUBLE = _PropertyTypeInfo(True, "double")
469 ENUM = _PropertyTypeInfo(False, "enum")
470 FUNCTION = _PropertyTypeInfo(False, "function")
471 INT64 = _PropertyTypeInfo(True, "int64")
472 INTEGER = _PropertyTypeInfo(True, "integer")
473 OBJECT = _PropertyTypeInfo(False, "object")
474 REF = _PropertyTypeInfo(False, "ref")
475 STRING = _PropertyTypeInfo(True, "string")
[email protected]cfe484902012-02-15 14:52:32476
[email protected]0853bcf2013-11-06 05:14:33477
[email protected]cb5670c2013-04-10 06:31:08478@memoize
[email protected]4ba6bdc2012-06-18 20:40:14479def UnixName(name):
[email protected]cb5670c2013-04-10 06:31:08480 '''Returns the unix_style name for a given lowerCamelCase string.
481 '''
482 unix_name = []
483 for i, c in enumerate(name):
[email protected]e11b9aa2013-07-13 00:05:42484 if c.isupper() and i > 0 and name[i - 1] != '_':
[email protected]cb5670c2013-04-10 06:31:08485 # Replace lowerUpper with lower_Upper.
486 if name[i - 1].islower():
487 unix_name.append('_')
488 # Replace ACMEWidgets with ACME_Widgets
489 elif i + 1 < len(name) and name[i + 1].islower():
490 unix_name.append('_')
491 if c == '.':
492 # Replace hello.world with hello_world.
493 unix_name.append('_')
494 else:
495 # Everything is lowercase.
496 unix_name.append(c.lower())
497 return ''.join(unix_name)
[email protected]cfe484902012-02-15 14:52:32498
[email protected]0853bcf2013-11-06 05:14:33499
[email protected]fad5da262014-05-15 08:04:00500@memoize
501def CamelName(snake):
502 ''' Converts a snake_cased_string to a camelCasedOne. '''
503 pieces = snake.split('_')
504 camel = []
505 for i, piece in enumerate(pieces):
506 if i == 0:
507 camel.append(piece)
508 else:
509 camel.append(piece.capitalize())
510 return ''.join(camel)
511
512
[email protected]0b255f002012-10-05 01:58:47513def _StripNamespace(name, namespace):
514 if name.startswith(namespace.name + '.'):
515 return name[len(namespace.name + '.'):]
516 return name
517
[email protected]0853bcf2013-11-06 05:14:33518
[email protected]116f0a3a2012-04-19 04:22:38519def _GetModelHierarchy(entity):
[email protected]feba21e2012-03-02 15:05:27520 """Returns the hierarchy of the given model entity."""
521 hierarchy = []
[email protected]242d5e7a2013-01-17 06:50:31522 while entity is not None:
523 hierarchy.append(getattr(entity, 'name', repr(entity)))
524 if isinstance(entity, Namespace):
525 hierarchy.insert(0, ' in %s' % entity.source_file)
526 entity = getattr(entity, 'parent', None)
[email protected]feba21e2012-03-02 15:05:27527 hierarchy.reverse()
528 return hierarchy
[email protected]116f0a3a2012-04-19 04:22:38529
[email protected]0853bcf2013-11-06 05:14:33530
[email protected]242d5e7a2013-01-17 06:50:31531def _GetTypes(parent, json, namespace, origin):
532 """Creates Type objects extracted from |json|.
[email protected]116f0a3a2012-04-19 04:22:38533 """
[email protected]242d5e7a2013-01-17 06:50:31534 types = OrderedDict()
[email protected]116f0a3a2012-04-19 04:22:38535 for type_json in json.get('types', []):
[email protected]242d5e7a2013-01-17 06:50:31536 type_ = Type(parent, type_json['id'], type_json, namespace, origin)
537 types[type_.name] = type_
538 return types
[email protected]116f0a3a2012-04-19 04:22:38539
[email protected]0853bcf2013-11-06 05:14:33540
[email protected]242d5e7a2013-01-17 06:50:31541def _GetFunctions(parent, json, namespace):
542 """Creates Function objects extracted from |json|.
[email protected]116f0a3a2012-04-19 04:22:38543 """
[email protected]242d5e7a2013-01-17 06:50:31544 functions = OrderedDict()
[email protected]116f0a3a2012-04-19 04:22:38545 for function_json in json.get('functions', []):
[email protected]242d5e7a2013-01-17 06:50:31546 function = Function(parent,
547 function_json['name'],
548 function_json,
549 namespace,
550 Origin(from_json=True))
551 functions[function.name] = function
552 return functions
[email protected]116f0a3a2012-04-19 04:22:38553
[email protected]0853bcf2013-11-06 05:14:33554
[email protected]242d5e7a2013-01-17 06:50:31555def _GetEvents(parent, json, namespace):
556 """Creates Function objects generated from the events in |json|.
[email protected]b741e8f2012-07-16 21:47:24557 """
[email protected]242d5e7a2013-01-17 06:50:31558 events = OrderedDict()
[email protected]b741e8f2012-07-16 21:47:24559 for event_json in json.get('events', []):
[email protected]242d5e7a2013-01-17 06:50:31560 event = Function(parent,
561 event_json['name'],
562 event_json,
563 namespace,
564 Origin(from_client=True))
565 events[event.name] = event
566 return events
[email protected]b741e8f2012-07-16 21:47:24567
[email protected]0853bcf2013-11-06 05:14:33568
[email protected]242d5e7a2013-01-17 06:50:31569def _GetProperties(parent, json, namespace, origin):
570 """Generates Property objects extracted from |json|.
[email protected]116f0a3a2012-04-19 04:22:38571 """
[email protected]242d5e7a2013-01-17 06:50:31572 properties = OrderedDict()
[email protected]116f0a3a2012-04-19 04:22:38573 for name, property_json in json.get('properties', {}).items():
[email protected]627b54d2013-02-04 23:53:59574 properties[name] = Property(parent, name, property_json, namespace, origin)
[email protected]242d5e7a2013-01-17 06:50:31575 return properties
[email protected]4636c832013-01-11 02:10:11576
[email protected]0853bcf2013-11-06 05:14:33577
[email protected]4636c832013-01-11 02:10:11578class _PlatformInfo(_Enum):
579 def __init__(self, name):
580 _Enum.__init__(self, name)
581
[email protected]0853bcf2013-11-06 05:14:33582
[email protected]4636c832013-01-11 02:10:11583class Platforms(object):
584 """Enum of the possible platforms.
585 """
586 CHROMEOS = _PlatformInfo("chromeos")
587 CHROMEOS_TOUCH = _PlatformInfo("chromeos_touch")
588 LINUX = _PlatformInfo("linux")
589 MAC = _PlatformInfo("mac")
590 WIN = _PlatformInfo("win")
591
[email protected]0853bcf2013-11-06 05:14:33592
[email protected]4636c832013-01-11 02:10:11593def _GetPlatforms(json):
[email protected]e0eec63f2013-10-30 05:28:58594 if 'platforms' not in json or json['platforms'] == None:
[email protected]4636c832013-01-11 02:10:11595 return None
[email protected]e0eec63f2013-10-30 05:28:58596 # Sanity check: platforms should not be an empty list.
597 if not json['platforms']:
598 raise ValueError('"platforms" cannot be an empty list')
[email protected]4636c832013-01-11 02:10:11599 platforms = []
600 for platform_name in json['platforms']:
601 for platform_enum in _Enum.GetAll(Platforms):
602 if platform_name == platform_enum.name:
603 platforms.append(platform_enum)
604 break
605 return platforms