blob: ed8a2ec404edef066279720ad422c3ee7a6c4a43 [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
[email protected]4636c832013-01-11 02:10:1130 def AddNamespace(self, json, source_file, include_compiler_options=False):
[email protected]a1f774972012-04-17 02:11:0931 """Add a namespace's json to the model and returns the namespace.
[email protected]15f08dd2012-01-27 07:29:4832 """
[email protected]4636c832013-01-11 02:10:1133 namespace = Namespace(json,
34 source_file,
35 include_compiler_options=include_compiler_options)
[email protected]15f08dd2012-01-27 07:29:4836 self.namespaces[namespace.name] = namespace
37 return namespace
38
[email protected]0853bcf2013-11-06 05:14:3339
40def CreateFeature(name, model):
41 if isinstance(model, dict):
42 return SimpleFeature(name, model)
43 return ComplexFeature(name, [SimpleFeature(name, child) for child in model])
44
45
46class ComplexFeature(object):
47 """A complex feature which may be made of several simple features.
48
49 Properties:
50 - |name| the name of the feature
51 - |unix_name| the unix_name of the feature
52 - |feature_list| a list of simple features which make up the feature
53 """
54 def __init__(self, feature_name, features):
55 self.name = feature_name
56 self.unix_name = UnixName(self.name)
57 self.feature_list = features
58
59class SimpleFeature(object):
60 """A simple feature, which can make up a complex feature, as specified in
61 files such as chrome/common/extensions/api/_permission_features.json.
62
63 Properties:
64 - |name| the name of the feature
65 - |unix_name| the unix_name of the feature
66 - |channel| the channel where the feature is released
67 - |extension_types| the types which can use the feature
68 - |whitelist| a list of extensions allowed to use the feature
69 """
70 def __init__(self, feature_name, feature_def):
71 self.name = feature_name
72 self.unix_name = UnixName(self.name)
73 self.channel = feature_def['channel']
74 self.extension_types = feature_def['extension_types']
75 self.whitelist = feature_def.get('whitelist')
76
77
[email protected]15f08dd2012-01-27 07:29:4878class Namespace(object):
79 """An API namespace.
[email protected]cfe484902012-02-15 14:52:3280
81 Properties:
82 - |name| the name of the namespace
[email protected]8426f8d72013-06-23 04:24:5583 - |description| the description of the namespace
[email protected]29163bc2014-01-27 21:50:5984 - |deprecated| a reason and possible alternative for a deprecated api
[email protected]712eca0f2012-02-21 01:13:0785 - |unix_name| the unix_name of the namespace
86 - |source_file| the file that contained the namespace definition
87 - |source_file_dir| the directory component of |source_file|
88 - |source_file_filename| the filename component of |source_file|
[email protected]4636c832013-01-11 02:10:1189 - |platforms| if not None, the list of platforms that the namespace is
90 available to
[email protected]cfe484902012-02-15 14:52:3291 - |types| a map of type names to their model.Type
92 - |functions| a map of function names to their model.Function
[email protected]b741e8f2012-07-16 21:47:2493 - |events| a map of event names to their model.Function
[email protected]116f0a3a2012-04-19 04:22:3894 - |properties| a map of property names to their model.Property
[email protected]bee7a7932013-08-12 23:45:3895 - |compiler_options| the compiler_options dict, only not empty if
[email protected]4636c832013-01-11 02:10:1196 |include_compiler_options| is True
[email protected]15f08dd2012-01-27 07:29:4897 """
[email protected]4636c832013-01-11 02:10:1198 def __init__(self, json, source_file, include_compiler_options=False):
[email protected]15f08dd2012-01-27 07:29:4899 self.name = json['namespace']
[email protected]8426f8d72013-06-23 04:24:55100 if 'description' not in json:
[email protected]a081aeb2013-07-09 20:52:47101 # TODO(kalman): Go back to throwing an error here.
102 print('%s must have a "description" field. This will appear '
[email protected]8426f8d72013-06-23 04:24:55103 'on the API summary page.' % self.name)
[email protected]a081aeb2013-07-09 20:52:47104 json['description'] = ''
105 self.description = json['description']
[email protected]29163bc2014-01-27 21:50:59106 self.deprecated = json.get('deprecated', None)
[email protected]4ba6bdc2012-06-18 20:40:14107 self.unix_name = UnixName(self.name)
[email protected]15f08dd2012-01-27 07:29:48108 self.source_file = source_file
109 self.source_file_dir, self.source_file_filename = os.path.split(source_file)
[email protected]70e263e2014-02-09 10:45:09110 self.short_filename = os.path.basename(source_file).split('.')[0]
[email protected]feba21e2012-03-02 15:05:27111 self.parent = None
[email protected]4636c832013-01-11 02:10:11112 self.platforms = _GetPlatforms(json)
[email protected]242d5e7a2013-01-17 06:50:31113 toplevel_origin = Origin(from_client=True, from_json=True)
114 self.types = _GetTypes(self, json, self, toplevel_origin)
115 self.functions = _GetFunctions(self, json, self)
116 self.events = _GetEvents(self, json, self)
117 self.properties = _GetProperties(self, json, self, toplevel_origin)
[email protected]03e5ffe2013-11-07 01:54:53118 if include_compiler_options:
119 self.compiler_options = json.get('compiler_options', {})
120 else:
121 self.compiler_options = {}
[email protected]0b022482013-10-03 19:38:05122 self.documentation_options = json.get('documentation_options', {})
[email protected]15f08dd2012-01-27 07:29:48123
[email protected]0853bcf2013-11-06 05:14:33124
[email protected]242d5e7a2013-01-17 06:50:31125class Origin(object):
126 """Stores the possible origin of model object as a pair of bools. These are:
127
128 |from_client| indicating that instances can originate from users of
129 generated code (for example, function results), or
130 |from_json| indicating that instances can originate from the JSON (for
131 example, function parameters)
132
133 It is possible for model objects to originate from both the client and json,
134 for example Types defined in the top-level schema, in which case both
135 |from_client| and |from_json| would be True.
136 """
137 def __init__(self, from_client=False, from_json=False):
138 if not from_client and not from_json:
139 raise ValueError('One of from_client or from_json must be true')
140 self.from_client = from_client
141 self.from_json = from_json
142
[email protected]0853bcf2013-11-06 05:14:33143
[email protected]15f08dd2012-01-27 07:29:48144class Type(object):
145 """A Type defined in the json.
[email protected]cfe484902012-02-15 14:52:32146
147 Properties:
148 - |name| the type name
[email protected]242d5e7a2013-01-17 06:50:31149 - |namespace| the Type's namespace
[email protected]cfe484902012-02-15 14:52:32150 - |description| the description of the type (if provided)
[email protected]feba21e2012-03-02 15:05:27151 - |properties| a map of property unix_names to their model.Property
152 - |functions| a map of function names to their model.Function
[email protected]d32b8e52012-07-23 18:40:08153 - |events| a map of event names to their model.Event
[email protected]242d5e7a2013-01-17 06:50:31154 - |origin| the Origin of the type
155 - |property_type| the PropertyType of this Type
[email protected]cf6d0b32012-04-12 04:30:22156 - |item_type| if this is an array, the type of items in the array
[email protected]0b255f002012-10-05 01:58:47157 - |simple_name| the name of this Type without a namespace
[email protected]242d5e7a2013-01-17 06:50:31158 - |additional_properties| the type of the additional properties, if any is
159 specified
[email protected]15f08dd2012-01-27 07:29:48160 """
[email protected]242d5e7a2013-01-17 06:50:31161 def __init__(self,
162 parent,
163 name,
164 json,
165 namespace,
166 origin):
167 self.name = name
168 self.namespace = namespace
169 self.simple_name = _StripNamespace(self.name, namespace)
170 self.unix_name = UnixName(self.name)
171 self.description = json.get('description', None)
172 self.origin = origin
173 self.parent = parent
174 self.instance_of = json.get('isInstanceOf', None)
175
176 # TODO(kalman): Only objects need functions/events/properties, but callers
177 # assume that all types have them. Fix this.
178 self.functions = _GetFunctions(self, json, namespace)
179 self.events = _GetEvents(self, json, namespace)
180 self.properties = _GetProperties(self, json, namespace, origin)
181
182 json_type = json.get('type', None)
183 if json_type == 'array':
184 self.property_type = PropertyType.ARRAY
185 self.item_type = Type(
186 self, '%sType' % name, json['items'], namespace, origin)
187 elif '$ref' in json:
188 self.property_type = PropertyType.REF
189 self.ref_type = json['$ref']
190 elif 'enum' in json and json_type == 'string':
191 self.property_type = PropertyType.ENUM
[email protected]7f138d42013-11-01 05:27:27192 self.enum_values = [EnumValue(value) for value in json['enum']]
[email protected]fad5da262014-05-15 08:04:00193 self.cpp_enum_prefix_override = json.get('cpp_enum_prefix_override', None)
[email protected]242d5e7a2013-01-17 06:50:31194 elif json_type == 'any':
195 self.property_type = PropertyType.ANY
196 elif json_type == 'binary':
197 self.property_type = PropertyType.BINARY
198 elif json_type == 'boolean':
199 self.property_type = PropertyType.BOOLEAN
200 elif json_type == 'integer':
201 self.property_type = PropertyType.INTEGER
202 elif (json_type == 'double' or
203 json_type == 'number'):
204 self.property_type = PropertyType.DOUBLE
205 elif json_type == 'string':
206 self.property_type = PropertyType.STRING
207 elif 'choices' in json:
208 self.property_type = PropertyType.CHOICES
[email protected]e11b9aa2013-07-13 00:05:42209 def generate_type_name(type_json):
210 if 'items' in type_json:
211 return '%ss' % generate_type_name(type_json['items'])
212 if '$ref' in type_json:
213 return type_json['$ref']
214 if 'type' in type_json:
215 return type_json['type']
216 return None
217 self.choices = [
218 Type(self,
219 generate_type_name(choice) or 'choice%s' % i,
220 choice,
221 namespace,
222 origin)
223 for i, choice in enumerate(json['choices'])]
[email protected]242d5e7a2013-01-17 06:50:31224 elif json_type == 'object':
[email protected]cf6d0b32012-04-12 04:30:22225 if not (
[email protected]117afcf2013-08-30 02:38:09226 'isInstanceOf' in json or
[email protected]cf6d0b32012-04-12 04:30:22227 'properties' in json or
228 'additionalProperties' in json or
[email protected]e975d112012-07-31 22:12:43229 'functions' in json or
230 'events' in json):
[email protected]116f0a3a2012-04-19 04:22:38231 raise ParseException(self, name + " has no properties or functions")
[email protected]242d5e7a2013-01-17 06:50:31232 self.property_type = PropertyType.OBJECT
233 additional_properties_json = json.get('additionalProperties', None)
234 if additional_properties_json is not None:
235 self.additional_properties = Type(self,
236 'additionalProperties',
237 additional_properties_json,
238 namespace,
239 origin)
240 else:
241 self.additional_properties = None
242 elif json_type == 'function':
243 self.property_type = PropertyType.FUNCTION
244 # Sometimes we might have an unnamed function, e.g. if it's a property
245 # of an object. Use the name of the property in that case.
246 function_name = json.get('name', name)
247 self.function = Function(self, function_name, json, namespace, origin)
248 else:
249 raise ParseException(self, 'Unsupported JSON type %s' % json_type)
[email protected]15f08dd2012-01-27 07:29:48250
[email protected]0853bcf2013-11-06 05:14:33251
[email protected]15f08dd2012-01-27 07:29:48252class Function(object):
253 """A Function defined in the API.
[email protected]cfe484902012-02-15 14:52:32254
255 Properties:
256 - |name| the function name
[email protected]4636c832013-01-11 02:10:11257 - |platforms| if not None, the list of platforms that the function is
258 available to
[email protected]cfe484902012-02-15 14:52:32259 - |params| a list of parameters to the function (order matters). A separate
[email protected]4636c832013-01-11 02:10:11260 parameter is used for each choice of a 'choices' parameter
[email protected]9c7830ba2013-10-17 19:28:46261 - |deprecated| a reason and possible alternative for a deprecated function
[email protected]cfe484902012-02-15 14:52:32262 - |description| a description of the function (if provided)
263 - |callback| the callback parameter to the function. There should be exactly
[email protected]4636c832013-01-11 02:10:11264 one
[email protected]4b3f7852012-07-17 06:33:30265 - |optional| whether the Function is "optional"; this only makes sense to be
[email protected]4636c832013-01-11 02:10:11266 present when the Function is representing a callback property
[email protected]0b255f002012-10-05 01:58:47267 - |simple_name| the name of this Function without a namespace
[email protected]32096af2013-02-06 01:29:31268 - |returns| the return type of the function; None if the function does not
269 return a value
[email protected]15f08dd2012-01-27 07:29:48270 """
[email protected]0b255f002012-10-05 01:58:47271 def __init__(self,
272 parent,
[email protected]242d5e7a2013-01-17 06:50:31273 name,
[email protected]0b255f002012-10-05 01:58:47274 json,
275 namespace,
[email protected]242d5e7a2013-01-17 06:50:31276 origin):
277 self.name = name
[email protected]0b255f002012-10-05 01:58:47278 self.simple_name = _StripNamespace(self.name, namespace)
[email protected]4636c832013-01-11 02:10:11279 self.platforms = _GetPlatforms(json)
[email protected]15f08dd2012-01-27 07:29:48280 self.params = []
[email protected]feba21e2012-03-02 15:05:27281 self.description = json.get('description')
[email protected]9c7830ba2013-10-17 19:28:46282 self.deprecated = json.get('deprecated')
[email protected]15f08dd2012-01-27 07:29:48283 self.callback = None
[email protected]4b3f7852012-07-17 06:33:30284 self.optional = json.get('optional', False)
[email protected]feba21e2012-03-02 15:05:27285 self.parent = parent
[email protected]a9ead752012-05-24 02:08:45286 self.nocompile = json.get('nocompile')
[email protected]c0718352012-08-21 02:34:24287 options = json.get('options', {})
288 self.conditions = options.get('conditions', [])
289 self.actions = options.get('actions', [])
290 self.supports_listeners = options.get('supportsListeners', True)
291 self.supports_rules = options.get('supportsRules', False)
[email protected]c18d6712013-10-03 18:39:30292 self.supports_dom = options.get('supportsDom', False)
[email protected]242d5e7a2013-01-17 06:50:31293
[email protected]c0718352012-08-21 02:34:24294 def GeneratePropertyFromParam(p):
[email protected]627b54d2013-02-04 23:53:59295 return Property(self, p['name'], p, namespace, origin)
[email protected]db943992012-08-02 14:02:54296
[email protected]c0718352012-08-21 02:34:24297 self.filters = [GeneratePropertyFromParam(filter)
298 for filter in json.get('filters', [])]
[email protected]db943992012-08-02 14:02:54299 callback_param = None
[email protected]b741e8f2012-07-16 21:47:24300 for param in json.get('parameters', []):
[email protected]15f08dd2012-01-27 07:29:48301 if param.get('type') == 'function':
[email protected]db943992012-08-02 14:02:54302 if callback_param:
303 # No ParseException because the webstore has this.
304 # Instead, pretend all intermediate callbacks are properties.
305 self.params.append(GeneratePropertyFromParam(callback_param))
306 callback_param = param
[email protected]15f08dd2012-01-27 07:29:48307 else:
[email protected]db943992012-08-02 14:02:54308 self.params.append(GeneratePropertyFromParam(param))
309
310 if callback_param:
[email protected]0b255f002012-10-05 01:58:47311 self.callback = Function(self,
[email protected]242d5e7a2013-01-17 06:50:31312 callback_param['name'],
[email protected]0b255f002012-10-05 01:58:47313 callback_param,
314 namespace,
[email protected]242d5e7a2013-01-17 06:50:31315 Origin(from_client=True))
[email protected]db943992012-08-02 14:02:54316
[email protected]491e60d32012-07-20 01:03:13317 self.returns = None
318 if 'returns' in json:
[email protected]627b54d2013-02-04 23:53:59319 self.returns = Type(self,
320 '%sReturnType' % name,
321 json['returns'],
322 namespace,
323 origin)
[email protected]15f08dd2012-01-27 07:29:48324
[email protected]0853bcf2013-11-06 05:14:33325
[email protected]15f08dd2012-01-27 07:29:48326class Property(object):
327 """A property of a type OR a parameter to a function.
[email protected]cfe484902012-02-15 14:52:32328 Properties:
329 - |name| name of the property as in the json. This shouldn't change since
330 it is the key used to access DictionaryValues
331 - |unix_name| the unix_style_name of the property. Used as variable name
332 - |optional| a boolean representing whether the property is optional
333 - |description| a description of the property (if provided)
[email protected]242d5e7a2013-01-17 06:50:31334 - |type_| the model.Type of this property
[email protected]0b255f002012-10-05 01:58:47335 - |simple_name| the name of this Property without a namespace
[email protected]04afd692013-11-14 19:35:04336 - |deprecated| a reason and possible alternative for a deprecated property
[email protected]15f08dd2012-01-27 07:29:48337 """
[email protected]627b54d2013-02-04 23:53:59338 def __init__(self, parent, name, json, namespace, origin):
[email protected]242d5e7a2013-01-17 06:50:31339 """Creates a Property from JSON.
340 """
[email protected]627b54d2013-02-04 23:53:59341 self.parent = parent
342 self.name = name
343 self._unix_name = UnixName(self.name)
344 self._unix_name_used = False
345 self.origin = origin
346 self.simple_name = _StripNamespace(self.name, namespace)
347 self.description = json.get('description', None)
348 self.optional = json.get('optional', None)
349 self.instance_of = json.get('isInstanceOf', None)
[email protected]04afd692013-11-14 19:35:04350 self.deprecated = json.get('deprecated')
[email protected]242d5e7a2013-01-17 06:50:31351
352 # HACK: only support very specific value types.
353 is_allowed_value = (
354 '$ref' not in json and
355 ('type' not in json or json['type'] == 'integer'
356 or json['type'] == 'string'))
357
[email protected]627b54d2013-02-04 23:53:59358 self.value = None
[email protected]242d5e7a2013-01-17 06:50:31359 if 'value' in json and is_allowed_value:
[email protected]627b54d2013-02-04 23:53:59360 self.value = json['value']
[email protected]242d5e7a2013-01-17 06:50:31361 if 'type' not in json:
362 # Sometimes the type of the value is left out, and we need to figure
363 # it out for ourselves.
[email protected]627b54d2013-02-04 23:53:59364 if isinstance(self.value, int):
[email protected]242d5e7a2013-01-17 06:50:31365 json['type'] = 'integer'
[email protected]627b54d2013-02-04 23:53:59366 elif isinstance(self.value, basestring):
[email protected]242d5e7a2013-01-17 06:50:31367 json['type'] = 'string'
368 else:
369 # TODO(kalman): support more types as necessary.
370 raise ParseException(
[email protected]627b54d2013-02-04 23:53:59371 parent,
372 '"%s" is not a supported type for "value"' % type(self.value))
[email protected]242d5e7a2013-01-17 06:50:31373
[email protected]627b54d2013-02-04 23:53:59374 self.type_ = Type(parent, name, json, namespace, origin)
[email protected]cfe484902012-02-15 14:52:32375
376 def GetUnixName(self):
377 """Gets the property's unix_name. Raises AttributeError if not set.
378 """
[email protected]116f0a3a2012-04-19 04:22:38379 if not self._unix_name:
[email protected]cfe484902012-02-15 14:52:32380 raise AttributeError('No unix_name set on %s' % self.name)
381 self._unix_name_used = True
382 return self._unix_name
383
384 def SetUnixName(self, unix_name):
385 """Set the property's unix_name. Raises AttributeError if the unix_name has
386 already been used (GetUnixName has been called).
387 """
388 if unix_name == self._unix_name:
389 return
390 if self._unix_name_used:
391 raise AttributeError(
392 'Cannot set the unix_name on %s; '
393 'it is already used elsewhere as %s' %
394 (self.name, self._unix_name))
395 self._unix_name = unix_name
396
397 unix_name = property(GetUnixName, SetUnixName)
[email protected]15f08dd2012-01-27 07:29:48398
[email protected]7f138d42013-11-01 05:27:27399class EnumValue(object):
400 """A single value from an enum.
401 Properties:
402 - |name| name of the property as in the json.
403 - |description| a description of the property (if provided)
404 """
405 def __init__(self, json):
406 if isinstance(json, dict):
407 self.name = json['name']
408 self.description = json.get('description')
409 else:
410 self.name = json
411 self.description = None
412
[email protected]fad5da262014-05-15 08:04:00413 def CamelName(self):
414 return CamelName(self.name)
415
[email protected]4636c832013-01-11 02:10:11416class _Enum(object):
417 """Superclass for enum types with a "name" field, setting up repr/eq/ne.
418 Enums need to do this so that equality/non-equality work over pickling.
[email protected]fe027682012-08-21 01:51:34419 """
[email protected]4636c832013-01-11 02:10:11420 @staticmethod
421 def GetAll(cls):
422 """Yields all _Enum objects declared in |cls|.
423 """
424 for prop_key in dir(cls):
425 prop_value = getattr(cls, prop_key)
426 if isinstance(prop_value, _Enum):
427 yield prop_value
428
429 def __init__(self, name):
[email protected]fe027682012-08-21 01:51:34430 self.name = name
431
[email protected]dc5f2fecf2012-08-31 01:55:51432 def __eq__(self, other):
[email protected]4636c832013-01-11 02:10:11433 return type(other) == type(self) and other.name == self.name
[email protected]e15dccb2012-10-05 06:02:25434 def __ne__(self, other):
[email protected]e15dccb2012-10-05 06:02:25435 return not (self == other)
436
[email protected]e11b9aa2013-07-13 00:05:42437 def __repr__(self):
438 return self.name
439
440 def __str__(self):
441 return repr(self)
442
[email protected]0853bcf2013-11-06 05:14:33443
[email protected]4636c832013-01-11 02:10:11444class _PropertyTypeInfo(_Enum):
445 def __init__(self, is_fundamental, name):
446 _Enum.__init__(self, name)
447 self.is_fundamental = is_fundamental
448
[email protected]0853bcf2013-11-06 05:14:33449
[email protected]15f08dd2012-01-27 07:29:48450class PropertyType(object):
451 """Enum of different types of properties/parameters.
452 """
[email protected]242d5e7a2013-01-17 06:50:31453 ANY = _PropertyTypeInfo(False, "any")
[email protected]e11b9aa2013-07-13 00:05:42454 ARRAY = _PropertyTypeInfo(False, "array")
455 BINARY = _PropertyTypeInfo(False, "binary")
456 BOOLEAN = _PropertyTypeInfo(True, "boolean")
457 CHOICES = _PropertyTypeInfo(False, "choices")
458 DOUBLE = _PropertyTypeInfo(True, "double")
459 ENUM = _PropertyTypeInfo(False, "enum")
460 FUNCTION = _PropertyTypeInfo(False, "function")
461 INT64 = _PropertyTypeInfo(True, "int64")
462 INTEGER = _PropertyTypeInfo(True, "integer")
463 OBJECT = _PropertyTypeInfo(False, "object")
464 REF = _PropertyTypeInfo(False, "ref")
465 STRING = _PropertyTypeInfo(True, "string")
[email protected]cfe484902012-02-15 14:52:32466
[email protected]0853bcf2013-11-06 05:14:33467
[email protected]cb5670c2013-04-10 06:31:08468@memoize
[email protected]4ba6bdc2012-06-18 20:40:14469def UnixName(name):
[email protected]cb5670c2013-04-10 06:31:08470 '''Returns the unix_style name for a given lowerCamelCase string.
471 '''
472 unix_name = []
473 for i, c in enumerate(name):
[email protected]e11b9aa2013-07-13 00:05:42474 if c.isupper() and i > 0 and name[i - 1] != '_':
[email protected]cb5670c2013-04-10 06:31:08475 # Replace lowerUpper with lower_Upper.
476 if name[i - 1].islower():
477 unix_name.append('_')
478 # Replace ACMEWidgets with ACME_Widgets
479 elif i + 1 < len(name) and name[i + 1].islower():
480 unix_name.append('_')
481 if c == '.':
482 # Replace hello.world with hello_world.
483 unix_name.append('_')
484 else:
485 # Everything is lowercase.
486 unix_name.append(c.lower())
487 return ''.join(unix_name)
[email protected]cfe484902012-02-15 14:52:32488
[email protected]0853bcf2013-11-06 05:14:33489
[email protected]fad5da262014-05-15 08:04:00490@memoize
491def CamelName(snake):
492 ''' Converts a snake_cased_string to a camelCasedOne. '''
493 pieces = snake.split('_')
494 camel = []
495 for i, piece in enumerate(pieces):
496 if i == 0:
497 camel.append(piece)
498 else:
499 camel.append(piece.capitalize())
500 return ''.join(camel)
501
502
[email protected]0b255f002012-10-05 01:58:47503def _StripNamespace(name, namespace):
504 if name.startswith(namespace.name + '.'):
505 return name[len(namespace.name + '.'):]
506 return name
507
[email protected]0853bcf2013-11-06 05:14:33508
[email protected]116f0a3a2012-04-19 04:22:38509def _GetModelHierarchy(entity):
[email protected]feba21e2012-03-02 15:05:27510 """Returns the hierarchy of the given model entity."""
511 hierarchy = []
[email protected]242d5e7a2013-01-17 06:50:31512 while entity is not None:
513 hierarchy.append(getattr(entity, 'name', repr(entity)))
514 if isinstance(entity, Namespace):
515 hierarchy.insert(0, ' in %s' % entity.source_file)
516 entity = getattr(entity, 'parent', None)
[email protected]feba21e2012-03-02 15:05:27517 hierarchy.reverse()
518 return hierarchy
[email protected]116f0a3a2012-04-19 04:22:38519
[email protected]0853bcf2013-11-06 05:14:33520
[email protected]242d5e7a2013-01-17 06:50:31521def _GetTypes(parent, json, namespace, origin):
522 """Creates Type objects extracted from |json|.
[email protected]116f0a3a2012-04-19 04:22:38523 """
[email protected]242d5e7a2013-01-17 06:50:31524 types = OrderedDict()
[email protected]116f0a3a2012-04-19 04:22:38525 for type_json in json.get('types', []):
[email protected]242d5e7a2013-01-17 06:50:31526 type_ = Type(parent, type_json['id'], type_json, namespace, origin)
527 types[type_.name] = type_
528 return types
[email protected]116f0a3a2012-04-19 04:22:38529
[email protected]0853bcf2013-11-06 05:14:33530
[email protected]242d5e7a2013-01-17 06:50:31531def _GetFunctions(parent, json, namespace):
532 """Creates Function objects extracted from |json|.
[email protected]116f0a3a2012-04-19 04:22:38533 """
[email protected]242d5e7a2013-01-17 06:50:31534 functions = OrderedDict()
[email protected]116f0a3a2012-04-19 04:22:38535 for function_json in json.get('functions', []):
[email protected]242d5e7a2013-01-17 06:50:31536 function = Function(parent,
537 function_json['name'],
538 function_json,
539 namespace,
540 Origin(from_json=True))
541 functions[function.name] = function
542 return functions
[email protected]116f0a3a2012-04-19 04:22:38543
[email protected]0853bcf2013-11-06 05:14:33544
[email protected]242d5e7a2013-01-17 06:50:31545def _GetEvents(parent, json, namespace):
546 """Creates Function objects generated from the events in |json|.
[email protected]b741e8f2012-07-16 21:47:24547 """
[email protected]242d5e7a2013-01-17 06:50:31548 events = OrderedDict()
[email protected]b741e8f2012-07-16 21:47:24549 for event_json in json.get('events', []):
[email protected]242d5e7a2013-01-17 06:50:31550 event = Function(parent,
551 event_json['name'],
552 event_json,
553 namespace,
554 Origin(from_client=True))
555 events[event.name] = event
556 return events
[email protected]b741e8f2012-07-16 21:47:24557
[email protected]0853bcf2013-11-06 05:14:33558
[email protected]242d5e7a2013-01-17 06:50:31559def _GetProperties(parent, json, namespace, origin):
560 """Generates Property objects extracted from |json|.
[email protected]116f0a3a2012-04-19 04:22:38561 """
[email protected]242d5e7a2013-01-17 06:50:31562 properties = OrderedDict()
[email protected]116f0a3a2012-04-19 04:22:38563 for name, property_json in json.get('properties', {}).items():
[email protected]627b54d2013-02-04 23:53:59564 properties[name] = Property(parent, name, property_json, namespace, origin)
[email protected]242d5e7a2013-01-17 06:50:31565 return properties
[email protected]4636c832013-01-11 02:10:11566
[email protected]0853bcf2013-11-06 05:14:33567
[email protected]4636c832013-01-11 02:10:11568class _PlatformInfo(_Enum):
569 def __init__(self, name):
570 _Enum.__init__(self, name)
571
[email protected]0853bcf2013-11-06 05:14:33572
[email protected]4636c832013-01-11 02:10:11573class Platforms(object):
574 """Enum of the possible platforms.
575 """
576 CHROMEOS = _PlatformInfo("chromeos")
577 CHROMEOS_TOUCH = _PlatformInfo("chromeos_touch")
578 LINUX = _PlatformInfo("linux")
579 MAC = _PlatformInfo("mac")
580 WIN = _PlatformInfo("win")
581
[email protected]0853bcf2013-11-06 05:14:33582
[email protected]4636c832013-01-11 02:10:11583def _GetPlatforms(json):
[email protected]e0eec63f2013-10-30 05:28:58584 if 'platforms' not in json or json['platforms'] == None:
[email protected]4636c832013-01-11 02:10:11585 return None
[email protected]e0eec63f2013-10-30 05:28:58586 # Sanity check: platforms should not be an empty list.
587 if not json['platforms']:
588 raise ValueError('"platforms" cannot be an empty list')
[email protected]4636c832013-01-11 02:10:11589 platforms = []
590 for platform_name in json['platforms']:
591 for platform_enum in _Enum.GetAll(Platforms):
592 if platform_name == platform_enum.name:
593 platforms.append(platform_enum)
594 break
595 return platforms