| OLD | NEW |
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import copy | 5 import copy |
| 6 import os.path | 6 import os.path |
| 7 import re | 7 import re |
| 8 | 8 |
| 9 class ParseException(Exception): | 9 class ParseException(Exception): |
| 10 """Thrown when data in the model is invalid. | 10 """Thrown when data in the model is invalid. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 44 - |functions| a map of function names to their model.Function | 44 - |functions| a map of function names to their model.Function |
| 45 - |events| a map of event names to their model.Function | 45 - |events| a map of event names to their model.Function |
| 46 - |properties| a map of property names to their model.Property | 46 - |properties| a map of property names to their model.Property |
| 47 """ | 47 """ |
| 48 def __init__(self, json, source_file): | 48 def __init__(self, json, source_file): |
| 49 self.name = json['namespace'] | 49 self.name = json['namespace'] |
| 50 self.unix_name = UnixName(self.name) | 50 self.unix_name = UnixName(self.name) |
| 51 self.source_file = source_file | 51 self.source_file = source_file |
| 52 self.source_file_dir, self.source_file_filename = os.path.split(source_file) | 52 self.source_file_dir, self.source_file_filename = os.path.split(source_file) |
| 53 self.parent = None | 53 self.parent = None |
| 54 _AddTypes(self, json) | 54 _AddTypes(self, json, self) |
| 55 _AddFunctions(self, json) | 55 _AddFunctions(self, json, self) |
| 56 _AddEvents(self, json) | 56 _AddEvents(self, json, self) |
| 57 _AddProperties(self, json) | 57 _AddProperties(self, json, self) |
| 58 | 58 |
| 59 class Type(object): | 59 class Type(object): |
| 60 """A Type defined in the json. | 60 """A Type defined in the json. |
| 61 | 61 |
| 62 Properties: | 62 Properties: |
| 63 - |name| the type name | 63 - |name| the type name |
| 64 - |description| the description of the type (if provided) | 64 - |description| the description of the type (if provided) |
| 65 - |properties| a map of property unix_names to their model.Property | 65 - |properties| a map of property unix_names to their model.Property |
| 66 - |functions| a map of function names to their model.Function | 66 - |functions| a map of function names to their model.Function |
| 67 - |events| a map of event names to their model.Event | 67 - |events| a map of event names to their model.Event |
| 68 - |from_client| indicates that instances of the Type can originate from the | 68 - |from_client| indicates that instances of the Type can originate from the |
| 69 users of generated code, such as top-level types and function results | 69 users of generated code, such as top-level types and function results |
| 70 - |from_json| indicates that instances of the Type can originate from the | 70 - |from_json| indicates that instances of the Type can originate from the |
| 71 JSON (as described by the schema), such as top-level types and function | 71 JSON (as described by the schema), such as top-level types and function |
| 72 parameters | 72 parameters |
| 73 - |type_| the PropertyType of this Type | 73 - |type_| the PropertyType of this Type |
| 74 - |item_type| if this is an array, the type of items in the array | 74 - |item_type| if this is an array, the type of items in the array |
| 75 - |simple_name| the name of this Type without a namespace |
| 75 """ | 76 """ |
| 76 def __init__(self, parent, name, json): | 77 def __init__(self, parent, name, json, namespace): |
| 77 if json.get('type') == 'array': | 78 if json.get('type') == 'array': |
| 78 self.type_ = PropertyType.ARRAY | 79 self.type_ = PropertyType.ARRAY |
| 79 self.item_type = Property(self, name + "Element", json['items'], | 80 self.item_type = Property(self, |
| 81 name + "Element", |
| 82 json['items'], |
| 83 namespace, |
| 80 from_json=True, | 84 from_json=True, |
| 81 from_client=True) | 85 from_client=True) |
| 82 elif 'enum' in json: | 86 elif 'enum' in json: |
| 83 self.enum_values = [] | 87 self.enum_values = [] |
| 84 for value in json['enum']: | 88 for value in json['enum']: |
| 85 self.enum_values.append(value) | 89 self.enum_values.append(value) |
| 86 self.type_ = PropertyType.ENUM | 90 self.type_ = PropertyType.ENUM |
| 87 elif json.get('type') == 'string': | 91 elif json.get('type') == 'string': |
| 88 self.type_ = PropertyType.STRING | 92 self.type_ = PropertyType.STRING |
| 89 else: | 93 else: |
| 90 if not ( | 94 if not ( |
| 91 'properties' in json or | 95 'properties' in json or |
| 92 'additionalProperties' in json or | 96 'additionalProperties' in json or |
| 93 'functions' in json or | 97 'functions' in json or |
| 94 'events' in json): | 98 'events' in json): |
| 95 raise ParseException(self, name + " has no properties or functions") | 99 raise ParseException(self, name + " has no properties or functions") |
| 96 self.type_ = PropertyType.OBJECT | 100 self.type_ = PropertyType.OBJECT |
| 97 self.name = name | 101 self.name = name |
| 102 self.simple_name = _StripNamespace(self.name, namespace) |
| 98 self.unix_name = UnixName(self.name) | 103 self.unix_name = UnixName(self.name) |
| 99 self.description = json.get('description') | 104 self.description = json.get('description') |
| 100 self.from_json = True | 105 self.from_json = True |
| 101 self.from_client = True | 106 self.from_client = True |
| 102 self.parent = parent | 107 self.parent = parent |
| 103 self.instance_of = json.get('isInstanceOf', None) | 108 self.instance_of = json.get('isInstanceOf', None) |
| 104 _AddFunctions(self, json) | 109 _AddFunctions(self, json, namespace) |
| 105 _AddEvents(self, json) | 110 _AddEvents(self, json, namespace) |
| 106 _AddProperties(self, json, from_json=True, from_client=True) | 111 _AddProperties(self, json, namespace, from_json=True, from_client=True) |
| 107 | 112 |
| 108 additional_properties_key = 'additionalProperties' | 113 additional_properties_key = 'additionalProperties' |
| 109 additional_properties = json.get(additional_properties_key) | 114 additional_properties = json.get(additional_properties_key) |
| 110 if additional_properties: | 115 if additional_properties: |
| 111 self.properties[additional_properties_key] = Property( | 116 self.properties[additional_properties_key] = Property( |
| 112 self, | 117 self, |
| 113 additional_properties_key, | 118 additional_properties_key, |
| 114 additional_properties, | 119 additional_properties, |
| 120 namespace, |
| 115 is_additional_properties=True) | 121 is_additional_properties=True) |
| 116 | 122 |
| 117 class Function(object): | 123 class Function(object): |
| 118 """A Function defined in the API. | 124 """A Function defined in the API. |
| 119 | 125 |
| 120 Properties: | 126 Properties: |
| 121 - |name| the function name | 127 - |name| the function name |
| 122 - |params| a list of parameters to the function (order matters). A separate | 128 - |params| a list of parameters to the function (order matters). A separate |
| 123 parameter is used for each choice of a 'choices' parameter. | 129 parameter is used for each choice of a 'choices' parameter. |
| 124 - |description| a description of the function (if provided) | 130 - |description| a description of the function (if provided) |
| 125 - |callback| the callback parameter to the function. There should be exactly | 131 - |callback| the callback parameter to the function. There should be exactly |
| 126 one | 132 one |
| 127 - |optional| whether the Function is "optional"; this only makes sense to be | 133 - |optional| whether the Function is "optional"; this only makes sense to be |
| 128 present when the Function is representing a callback property. | 134 present when the Function is representing a callback property. |
| 135 - |simple_name| the name of this Function without a namespace |
| 129 """ | 136 """ |
| 130 def __init__(self, parent, json, from_json=False, from_client=False): | 137 def __init__(self, |
| 138 parent, |
| 139 json, |
| 140 namespace, |
| 141 from_json=False, |
| 142 from_client=False): |
| 131 self.name = json['name'] | 143 self.name = json['name'] |
| 144 self.simple_name = _StripNamespace(self.name, namespace) |
| 132 self.params = [] | 145 self.params = [] |
| 133 self.description = json.get('description') | 146 self.description = json.get('description') |
| 134 self.callback = None | 147 self.callback = None |
| 135 self.optional = json.get('optional', False) | 148 self.optional = json.get('optional', False) |
| 136 self.parent = parent | 149 self.parent = parent |
| 137 self.nocompile = json.get('nocompile') | 150 self.nocompile = json.get('nocompile') |
| 138 options = json.get('options', {}) | 151 options = json.get('options', {}) |
| 139 self.conditions = options.get('conditions', []) | 152 self.conditions = options.get('conditions', []) |
| 140 self.actions = options.get('actions', []) | 153 self.actions = options.get('actions', []) |
| 141 self.supports_listeners = options.get('supportsListeners', True) | 154 self.supports_listeners = options.get('supportsListeners', True) |
| 142 self.supports_rules = options.get('supportsRules', False) | 155 self.supports_rules = options.get('supportsRules', False) |
| 143 def GeneratePropertyFromParam(p): | 156 def GeneratePropertyFromParam(p): |
| 144 return Property(self, | 157 return Property(self, |
| 145 p['name'], p, | 158 p['name'], p, |
| 159 namespace, |
| 146 from_json=from_json, | 160 from_json=from_json, |
| 147 from_client=from_client) | 161 from_client=from_client) |
| 148 | 162 |
| 149 self.filters = [GeneratePropertyFromParam(filter) | 163 self.filters = [GeneratePropertyFromParam(filter) |
| 150 for filter in json.get('filters', [])] | 164 for filter in json.get('filters', [])] |
| 151 callback_param = None | 165 callback_param = None |
| 152 for param in json.get('parameters', []): | 166 for param in json.get('parameters', []): |
| 153 | 167 |
| 154 if param.get('type') == 'function': | 168 if param.get('type') == 'function': |
| 155 if callback_param: | 169 if callback_param: |
| 156 # No ParseException because the webstore has this. | 170 # No ParseException because the webstore has this. |
| 157 # Instead, pretend all intermediate callbacks are properties. | 171 # Instead, pretend all intermediate callbacks are properties. |
| 158 self.params.append(GeneratePropertyFromParam(callback_param)) | 172 self.params.append(GeneratePropertyFromParam(callback_param)) |
| 159 callback_param = param | 173 callback_param = param |
| 160 else: | 174 else: |
| 161 self.params.append(GeneratePropertyFromParam(param)) | 175 self.params.append(GeneratePropertyFromParam(param)) |
| 162 | 176 |
| 163 if callback_param: | 177 if callback_param: |
| 164 self.callback = Function(self, callback_param, from_client=True) | 178 self.callback = Function(self, |
| 179 callback_param, |
| 180 namespace, |
| 181 from_client=True) |
| 165 | 182 |
| 166 self.returns = None | 183 self.returns = None |
| 167 if 'returns' in json: | 184 if 'returns' in json: |
| 168 self.returns = Property(self, 'return', json['returns']) | 185 self.returns = Property(self, 'return', json['returns'], namespace) |
| 169 | 186 |
| 170 class Property(object): | 187 class Property(object): |
| 171 """A property of a type OR a parameter to a function. | 188 """A property of a type OR a parameter to a function. |
| 172 | 189 |
| 173 Properties: | 190 Properties: |
| 174 - |name| name of the property as in the json. This shouldn't change since | 191 - |name| name of the property as in the json. This shouldn't change since |
| 175 it is the key used to access DictionaryValues | 192 it is the key used to access DictionaryValues |
| 176 - |unix_name| the unix_style_name of the property. Used as variable name | 193 - |unix_name| the unix_style_name of the property. Used as variable name |
| 177 - |optional| a boolean representing whether the property is optional | 194 - |optional| a boolean representing whether the property is optional |
| 178 - |description| a description of the property (if provided) | 195 - |description| a description of the property (if provided) |
| 179 - |type_| the model.PropertyType of this property | 196 - |type_| the model.PropertyType of this property |
| 180 - |compiled_type| the model.PropertyType that this property should be | 197 - |compiled_type| the model.PropertyType that this property should be |
| 181 compiled to from the JSON. Defaults to |type_|. | 198 compiled to from the JSON. Defaults to |type_|. |
| 182 - |ref_type| the type that the REF property is referencing. Can be used to | 199 - |ref_type| the type that the REF property is referencing. Can be used to |
| 183 map to its model.Type | 200 map to its model.Type |
| 184 - |item_type| a model.Property representing the type of each element in an | 201 - |item_type| a model.Property representing the type of each element in an |
| 185 ARRAY | 202 ARRAY |
| 186 - |properties| the properties of an OBJECT parameter | 203 - |properties| the properties of an OBJECT parameter |
| 187 - |from_client| indicates that instances of the Type can originate from the | 204 - |from_client| indicates that instances of the Type can originate from the |
| 188 users of generated code, such as top-level types and function results | 205 users of generated code, such as top-level types and function results |
| 189 - |from_json| indicates that instances of the Type can originate from the | 206 - |from_json| indicates that instances of the Type can originate from the |
| 190 JSON (as described by the schema), such as top-level types and function | 207 JSON (as described by the schema), such as top-level types and function |
| 191 parameters | 208 parameters |
| 209 - |simple_name| the name of this Property without a namespace |
| 192 """ | 210 """ |
| 193 | 211 |
| 194 def __init__(self, parent, name, json, is_additional_properties=False, | 212 def __init__(self, |
| 195 from_json=False, from_client=False): | 213 parent, |
| 214 name, |
| 215 json, |
| 216 namespace, |
| 217 is_additional_properties=False, |
| 218 from_json=False, |
| 219 from_client=False): |
| 196 self.name = name | 220 self.name = name |
| 221 self.simple_name = _StripNamespace(self.name, namespace) |
| 197 self._unix_name = UnixName(self.name) | 222 self._unix_name = UnixName(self.name) |
| 198 self._unix_name_used = False | 223 self._unix_name_used = False |
| 199 self.optional = json.get('optional', False) | 224 self.optional = json.get('optional', False) |
| 200 self.functions = {} | 225 self.functions = {} |
| 201 self.has_value = False | 226 self.has_value = False |
| 202 self.description = json.get('description') | 227 self.description = json.get('description') |
| 203 self.parent = parent | 228 self.parent = parent |
| 204 self.from_json = from_json | 229 self.from_json = from_json |
| 205 self.from_client = from_client | 230 self.from_client = from_client |
| 206 self.instance_of = json.get('isInstanceOf', None) | 231 self.instance_of = json.get('isInstanceOf', None) |
| 207 _AddProperties(self, json) | 232 _AddProperties(self, json, namespace) |
| 208 if is_additional_properties: | 233 if is_additional_properties: |
| 209 self.type_ = PropertyType.ADDITIONAL_PROPERTIES | 234 self.type_ = PropertyType.ADDITIONAL_PROPERTIES |
| 210 elif '$ref' in json: | 235 elif '$ref' in json: |
| 211 self.ref_type = json['$ref'] | 236 self.ref_type = json['$ref'] |
| 212 self.type_ = PropertyType.REF | 237 self.type_ = PropertyType.REF |
| 213 elif 'enum' in json and json.get('type') == 'string': | 238 elif 'enum' in json and json.get('type') == 'string': |
| 214 # Non-string enums (as in the case of [legalValues=(1,2)]) should fall | 239 # Non-string enums (as in the case of [legalValues=(1,2)]) should fall |
| 215 # through to the next elif. | 240 # through to the next elif. |
| 216 self.enum_values = [] | 241 self.enum_values = [] |
| 217 for value in json['enum']: | 242 for value in json['enum']: |
| 218 self.enum_values.append(value) | 243 self.enum_values.append(value) |
| 219 self.type_ = PropertyType.ENUM | 244 self.type_ = PropertyType.ENUM |
| 220 elif 'type' in json: | 245 elif 'type' in json: |
| 221 self.type_ = self._JsonTypeToPropertyType(json['type']) | 246 self.type_ = self._JsonTypeToPropertyType(json['type']) |
| 222 if self.type_ == PropertyType.ARRAY: | 247 if self.type_ == PropertyType.ARRAY: |
| 223 self.item_type = Property(self, name + "Element", json['items'], | 248 self.item_type = Property(self, |
| 224 from_json=from_json, | 249 name + "Element", |
| 225 from_client=from_client) | 250 json['items'], |
| 251 namespace, |
| 252 from_json=from_json, |
| 253 from_client=from_client) |
| 226 elif self.type_ == PropertyType.OBJECT: | 254 elif self.type_ == PropertyType.OBJECT: |
| 227 # These members are read when this OBJECT Property is used as a Type | 255 # These members are read when this OBJECT Property is used as a Type |
| 228 type_ = Type(self, self.name, json) | 256 type_ = Type(self, self.name, json, namespace) |
| 229 # self.properties will already have some value from |_AddProperties|. | 257 # self.properties will already have some value from |_AddProperties|. |
| 230 self.properties.update(type_.properties) | 258 self.properties.update(type_.properties) |
| 231 self.functions = type_.functions | 259 self.functions = type_.functions |
| 232 elif 'choices' in json: | 260 elif 'choices' in json: |
| 233 if not json['choices'] or len(json['choices']) == 0: | 261 if not json['choices'] or len(json['choices']) == 0: |
| 234 raise ParseException(self, 'Choices has no choices') | 262 raise ParseException(self, 'Choices has no choices') |
| 235 self.choices = {} | 263 self.choices = {} |
| 236 self.type_ = PropertyType.CHOICES | 264 self.type_ = PropertyType.CHOICES |
| 237 self.compiled_type = self.type_ | 265 self.compiled_type = self.type_ |
| 238 for choice_json in json['choices']: | 266 for choice_json in json['choices']: |
| 239 choice = Property(self, self.name, choice_json, | 267 choice = Property(self, |
| 240 from_json=from_json, | 268 self.name, |
| 241 from_client=from_client) | 269 choice_json, |
| 270 namespace, |
| 271 from_json=from_json, |
| 272 from_client=from_client) |
| 242 choice.unix_name = UnixName(self.name + choice.type_.name) | 273 choice.unix_name = UnixName(self.name + choice.type_.name) |
| 243 # The existence of any single choice is optional | 274 # The existence of any single choice is optional |
| 244 choice.optional = True | 275 choice.optional = True |
| 245 self.choices[choice.type_] = choice | 276 self.choices[choice.type_] = choice |
| 246 elif 'value' in json: | 277 elif 'value' in json: |
| 247 self.has_value = True | 278 self.has_value = True |
| 248 self.value = json['value'] | 279 self.value = json['value'] |
| 249 if type(self.value) == int: | 280 if type(self.value) == int: |
| 250 self.type_ = PropertyType.INTEGER | 281 self.type_ = PropertyType.INTEGER |
| 251 self.compiled_type = self.type_ | 282 self.compiled_type = self.type_ |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 346 def UnixName(name): | 377 def UnixName(name): |
| 347 """Returns the unix_style name for a given lowerCamelCase string. | 378 """Returns the unix_style name for a given lowerCamelCase string. |
| 348 """ | 379 """ |
| 349 # First replace any lowerUpper patterns with lower_Upper. | 380 # First replace any lowerUpper patterns with lower_Upper. |
| 350 s1 = re.sub('([a-z])([A-Z])', r'\1_\2', name) | 381 s1 = re.sub('([a-z])([A-Z])', r'\1_\2', name) |
| 351 # Now replace any ACMEWidgets patterns with ACME_Widgets | 382 # Now replace any ACMEWidgets patterns with ACME_Widgets |
| 352 s2 = re.sub('([A-Z]+)([A-Z][a-z])', r'\1_\2', s1) | 383 s2 = re.sub('([A-Z]+)([A-Z][a-z])', r'\1_\2', s1) |
| 353 # Finally, replace any remaining periods, and make lowercase. | 384 # Finally, replace any remaining periods, and make lowercase. |
| 354 return s2.replace('.', '_').lower() | 385 return s2.replace('.', '_').lower() |
| 355 | 386 |
| 387 def _StripNamespace(name, namespace): |
| 388 if name.startswith(namespace.name + '.'): |
| 389 return name[len(namespace.name + '.'):] |
| 390 return name |
| 391 |
| 356 def _GetModelHierarchy(entity): | 392 def _GetModelHierarchy(entity): |
| 357 """Returns the hierarchy of the given model entity.""" | 393 """Returns the hierarchy of the given model entity.""" |
| 358 hierarchy = [] | 394 hierarchy = [] |
| 359 while entity: | 395 while entity: |
| 360 try: | 396 try: |
| 361 hierarchy.append(entity.name) | 397 hierarchy.append(entity.name) |
| 362 except AttributeError: | 398 except AttributeError: |
| 363 hierarchy.append(repr(entity)) | 399 hierarchy.append(repr(entity)) |
| 364 entity = entity.parent | 400 entity = entity.parent |
| 365 hierarchy.reverse() | 401 hierarchy.reverse() |
| 366 return hierarchy | 402 return hierarchy |
| 367 | 403 |
| 368 def _AddTypes(model, json): | 404 def _AddTypes(model, json, namespace): |
| 369 """Adds Type objects to |model| contained in the 'types' field of |json|. | 405 """Adds Type objects to |model| contained in the 'types' field of |json|. |
| 370 """ | 406 """ |
| 371 model.types = {} | 407 model.types = {} |
| 372 for type_json in json.get('types', []): | 408 for type_json in json.get('types', []): |
| 373 type_ = Type(model, type_json['id'], type_json) | 409 type_ = Type(model, type_json['id'], type_json, namespace) |
| 374 model.types[type_.name] = type_ | 410 model.types[type_.name] = type_ |
| 375 | 411 |
| 376 def _AddFunctions(model, json): | 412 def _AddFunctions(model, json, namespace): |
| 377 """Adds Function objects to |model| contained in the 'functions' field of | 413 """Adds Function objects to |model| contained in the 'functions' field of |
| 378 |json|. | 414 |json|. |
| 379 """ | 415 """ |
| 380 model.functions = {} | 416 model.functions = {} |
| 381 for function_json in json.get('functions', []): | 417 for function_json in json.get('functions', []): |
| 382 function = Function(model, function_json, from_json=True) | 418 function = Function(model, function_json, namespace, from_json=True) |
| 383 model.functions[function.name] = function | 419 model.functions[function.name] = function |
| 384 | 420 |
| 385 def _AddEvents(model, json): | 421 def _AddEvents(model, json, namespace): |
| 386 """Adds Function objects to |model| contained in the 'events' field of |json|. | 422 """Adds Function objects to |model| contained in the 'events' field of |json|. |
| 387 """ | 423 """ |
| 388 model.events = {} | 424 model.events = {} |
| 389 for event_json in json.get('events', []): | 425 for event_json in json.get('events', []): |
| 390 event = Function(model, event_json, from_client=True) | 426 event = Function(model, event_json, namespace, from_client=True) |
| 391 model.events[event.name] = event | 427 model.events[event.name] = event |
| 392 | 428 |
| 393 def _AddProperties(model, json, from_json=False, from_client=False): | 429 def _AddProperties(model, |
| 430 json, |
| 431 namespace, |
| 432 from_json=False, |
| 433 from_client=False): |
| 394 """Adds model.Property objects to |model| contained in the 'properties' field | 434 """Adds model.Property objects to |model| contained in the 'properties' field |
| 395 of |json|. | 435 of |json|. |
| 396 """ | 436 """ |
| 397 model.properties = {} | 437 model.properties = {} |
| 398 for name, property_json in json.get('properties', {}).items(): | 438 for name, property_json in json.get('properties', {}).items(): |
| 399 model.properties[name] = Property( | 439 model.properties[name] = Property( |
| 400 model, | 440 model, |
| 401 name, | 441 name, |
| 402 property_json, | 442 property_json, |
| 443 namespace, |
| 403 from_json=from_json, | 444 from_json=from_json, |
| 404 from_client=from_client) | 445 from_client=from_client) |
| OLD | NEW |