Chromium Code Reviews| 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 from copy import copy | 5 from copy import copy |
| 6 import logging | 6 import logging |
| 7 import os | 7 import os |
| 8 import posixpath | 8 import posixpath |
| 9 | 9 |
| 10 from data_source import DataSource | 10 from data_source import DataSource |
| 11 from docs_server_utils import StringIdentity | 11 from docs_server_utils import StringIdentity |
| 12 from environment import IsPreviewServer | 12 from environment import IsPreviewServer |
| 13 from extensions_paths import JSON_TEMPLATES, PRIVATE_TEMPLATES | 13 from extensions_paths import JSON_TEMPLATES, PRIVATE_TEMPLATES |
| 14 from file_system import FileNotFoundError | 14 from file_system import FileNotFoundError |
| 15 from future import Future, Collect | 15 from future import Future, Collect |
| 16 from platform_util import GetPlatforms | 16 from platform_util import GetPlatforms |
| 17 import third_party.json_schema_compiler.json_parse as json_parse | 17 import third_party.json_schema_compiler.json_parse as json_parse |
| 18 import third_party.json_schema_compiler.model as model | 18 import third_party.json_schema_compiler.model as model |
| 19 from environment import IsPreviewServer | 19 from environment import IsPreviewServer |
| 20 from third_party.json_schema_compiler.memoize import memoize | 20 from third_party.json_schema_compiler.memoize import memoize |
| 21 | 21 |
| 22 | 22 |
| 23 # The set of possible categories a node may belong to. | |
| 24 _NODE_CATEGORIES = ('types', 'functions', 'events', 'properties') | |
| 25 | |
| 26 | |
| 23 def _CreateId(node, prefix): | 27 def _CreateId(node, prefix): |
| 24 if node.parent is not None and not isinstance(node.parent, model.Namespace): | 28 if node.parent is not None and not isinstance(node.parent, model.Namespace): |
| 25 return '-'.join([prefix, node.parent.simple_name, node.simple_name]) | 29 return '-'.join([prefix, node.parent.simple_name, node.simple_name]) |
| 26 return '-'.join([prefix, node.simple_name]) | 30 return '-'.join([prefix, node.simple_name]) |
| 27 | 31 |
| 28 | 32 |
| 29 def _FormatValue(value): | 33 def _FormatValue(value): |
| 30 '''Inserts commas every three digits for integer values. It is magic. | 34 '''Inserts commas every three digits for integer values. It is magic. |
| 31 ''' | 35 ''' |
| 32 s = str(value) | 36 s = str(value) |
| 33 return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1]) | 37 return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1]) |
| 34 | 38 |
| 35 | 39 |
| 36 def _GetByNameDict(namespace): | 40 def _GetByNameDict(namespace): |
| 37 '''Returns a dictionary mapping names to named items from |namespace|. | 41 '''Returns a dictionary mapping names to named items from |namespace|. |
| 38 | 42 |
| 39 This lets us render specific API entities rather than the whole thing at once, | 43 This lets us render specific API entities rather than the whole thing at once, |
| 40 for example {{apis.manifestTypes.byName.ExternallyConnectable}}. | 44 for example {{apis.manifestTypes.byName.ExternallyConnectable}}. |
| 41 | 45 |
| 42 Includes items from namespace['types'], namespace['functions'], | 46 Includes items from namespace['types'], namespace['functions'], |
| 43 namespace['events'], and namespace['properties']. | 47 namespace['events'], and namespace['properties']. |
| 44 ''' | 48 ''' |
| 45 by_name = {} | 49 by_name = {} |
| 46 for item_type in ('types', 'functions', 'events', 'properties'): | 50 for item_type in _NODE_CATEGORIES: |
| 47 if item_type in namespace: | 51 if item_type in namespace: |
| 48 old_size = len(by_name) | 52 old_size = len(by_name) |
| 49 by_name.update( | 53 by_name.update( |
| 50 (item['name'], item) for item in namespace[item_type]) | 54 (item['name'], item) for item in namespace[item_type]) |
| 51 assert len(by_name) == old_size + len(namespace[item_type]), ( | 55 assert len(by_name) == old_size + len(namespace[item_type]), ( |
| 52 'Duplicate name in %r' % namespace) | 56 'Duplicate name in %r' % namespace) |
| 53 return by_name | 57 return by_name |
| 54 | 58 |
| 55 | 59 |
| 56 def _GetEventByNameFromEvents(events): | 60 def _GetEventByNameFromEvents(events): |
| 57 '''Parses the dictionary |events| to find the definitions of members of the | 61 '''Parses the dictionary |events| to find the definitions of members of the |
| 58 type Event. Returns a dictionary mapping the name of a member to that | 62 type Event. Returns a dictionary mapping the name of a member to that |
| 59 member's definition. | 63 member's definition. |
| 60 ''' | 64 ''' |
| 61 assert 'types' in events, \ | 65 assert 'types' in events, \ |
| 62 'The dictionary |events| must contain the key "types".' | 66 'The dictionary |events| must contain the key "types".' |
| 63 event_list = [t for t in events['types'] if t.get('name') == 'Event'] | 67 event_list = [t for t in events['types'] if t.get('name') == 'Event'] |
| 64 assert len(event_list) == 1, 'Exactly one type must be called "Event".' | 68 assert len(event_list) == 1, 'Exactly one type must be called "Event".' |
| 65 return _GetByNameDict(event_list[0]) | 69 return _GetByNameDict(event_list[0]) |
| 66 | 70 |
| 67 | 71 |
| 72 class _APINodeCursor(object): | |
| 73 '''An abstract representation of a node in an APISchemaGraph. | |
| 74 The current position in the graph is represented by a path into the | |
| 75 underlying dictionary. So if the APISchemaGraph is: | |
| 76 | |
| 77 { | |
| 78 'tabs': { | |
| 79 'types': { | |
| 80 'Tab': { | |
| 81 'properties': { | |
| 82 'url': { | |
| 83 ... | |
| 84 } | |
| 85 } | |
| 86 } | |
| 87 } | |
| 88 } | |
| 89 } | |
| 90 | |
| 91 then the 'url' property would be represented by: | |
| 92 | |
| 93 ['tabs', 'types', 'Tab', 'properties', 'url'] | |
| 94 ''' | |
| 95 | |
| 96 def __init__(self, availability_finder, namespace_name): | |
| 97 self._lookup_path = [] | |
| 98 self._node_availabilities = availability_finder.GetAPINodeAvailability( | |
| 99 namespace_name) | |
| 100 self._namespace_name = namespace_name | |
| 101 | |
| 102 def _AssertIsValidCategory(self, category): | |
| 103 assert category in _NODE_CATEGORIES, \ | |
| 104 '%s is not a valid category. Full path: %s' % (category, | |
| 105 self._lookup_path) | |
| 106 | |
| 107 def _GetParentPath(self): | |
| 108 '''Returns the path pointing to this node's parent. | |
| 109 ''' | |
| 110 assert len(self._lookup_path) > 1, \ | |
| 111 'Tried to look up parent for the top-level node.' | |
| 112 | |
| 113 # lookup_path[-1] is the name of the current node. If this lookup_path | |
| 114 # describes a regular node, then lookup_path[-2] will be a node category. | |
| 115 # Otherwise, it's an event callback or a function parameter. | |
| 116 if self._lookup_path[-2] not in _NODE_CATEGORIES: | |
| 117 if self._lookup_path[-1] == 'callback': | |
| 118 # This is an event callback, so lookup_path[-2] is the event | |
| 119 # node name, thus lookup_path[-3] must be 'events'. | |
| 120 assert self._lookup_path[-3] == 'events' | |
| 121 return self._lookup_path[:-1] | |
| 122 # This is a function parameter. | |
| 123 assert self._lookup_path[-2] == 'parameters' | |
| 124 return self._lookup_path[:-2] | |
| 125 # This is a regular node, so lookup_path[-2] should | |
| 126 # be a node category. | |
| 127 self._AssertIsValidCategory(self._lookup_path[-2]) | |
| 128 return self._lookup_path[:-2] | |
| 129 | |
| 130 def _LookupNodeAvailability(self): | |
| 131 '''Returns the ChannelInfo object for this node. | |
| 132 ''' | |
| 133 return self._node_availabilities.Lookup(self._namespace_name, | |
| 134 *self._lookup_path).annotation | |
| 135 | |
| 136 def _LookupParentNodeAvailability(self): | |
| 137 '''Returns the ChannelInfo object for this node's parent. | |
| 138 ''' | |
| 139 return self._node_availabilities.Lookup(self._namespace_name, | |
| 140 *self._GetParentPath()).annotation | |
| 141 | |
| 142 def _CheckNamespacePrefix(self): | |
| 143 '''API schemas may prepend the namespace name to top-level types | |
| 144 (e.g. declarativeWebRequest > types > declarativeWebRequest.IgnoreRules), | |
| 145 but just the base name (here, 'IgnoreRules') will be in the |lookup_path|. | |
| 146 Try creating an alternate |lookup_path| by adding the namespace name. | |
| 147 ''' | |
| 148 # lookup_path[0] is always the node category (e.g. types, functions, etc.). | |
| 149 # Thus, lookup_path[1] is always the top-level node name. | |
| 150 self._AssertIsValidCategory(self._lookup_path[0]) | |
| 151 base_name = self._lookup_path[1] | |
| 152 self._lookup_path[1] = '%s.%s' % (self._namespace_name, base_name) | |
| 153 try: | |
| 154 node_availability = self._LookupNodeAvailability() | |
| 155 if node_availability is not None: | |
| 156 return node_availability | |
| 157 finally: | |
| 158 # Restore lookup_path. | |
| 159 self._lookup_path[1] = base_name | |
| 160 return None | |
| 161 | |
| 162 def _CheckEventCallback(self): | |
| 163 '''Within API schemas, an event has a list of 'properties' that the event's | |
| 164 callback expects. The callback itself is not explicitly represented in the | |
| 165 schema. However, when creating an event node in _JSCModel, a callback node | |
| 166 is generated and acts as the parent for the event's properties. | |
| 167 Modify |lookup_path| to check the original schema format. | |
| 168 ''' | |
| 169 if 'events' in self._lookup_path: | |
| 170 assert 'callback' in self._lookup_path | |
| 171 callback_index = self._lookup_path.index('callback') | |
| 172 try: | |
| 173 self._lookup_path.pop(callback_index) | |
| 174 node_availability = self._LookupNodeAvailability() | |
| 175 finally: | |
| 176 self._lookup_path.insert(callback_index, 'callback') | |
| 177 return node_availability | |
| 178 return None | |
| 179 | |
| 180 def _LookupAvailability(self): | |
| 181 '''Runs all the lookup checks on self._lookup_path and | |
| 182 returns the node availability if found, None otherwise. | |
| 183 ''' | |
| 184 for lookup in (self._LookupNodeAvailability, | |
| 185 self._CheckEventCallback, | |
| 186 self._CheckNamespacePrefix): | |
| 187 node_availability = lookup() | |
| 188 if node_availability is not None: | |
| 189 return node_availability | |
| 190 return None | |
| 191 | |
| 192 def GetAvailability(self): | |
| 193 '''Returns availability information for this node. | |
| 194 ''' | |
| 195 node_availability = self._LookupAvailability() | |
| 196 if node_availability is None: | |
| 197 logging.warning('No availability found for: %s > %s' % | |
| 198 (self._namespace_name, ' > '.join(self._lookup_path))) | |
| 199 return None | |
| 200 | |
| 201 current_path = self._lookup_path | |
| 202 self._lookup_path = self._GetParentPath() | |
| 203 parent_node_availability = self._LookupAvailability() | |
| 204 self._lookup_path = current_path | |
|
not at google - send to devlin
2014/07/02 19:26:41
Again, please do this in a try..finally.
Though I
| |
| 205 # If the parent node availability couldn't be found, something | |
| 206 # is very wrong. | |
| 207 assert parent_node_availability is not None | |
| 208 | |
| 209 # Only render this node's availability if it differs from the parent | |
| 210 # node's availability. | |
| 211 if node_availability == parent_node_availability: | |
| 212 return None | |
| 213 return node_availability | |
| 214 | |
| 215 def Descend(self, *path): | |
| 216 '''Moves down the APISchemaGraph, following |path|. | |
| 217 ''' | |
| 218 class scope(object): | |
| 219 def __enter__(self2): | |
| 220 self._lookup_path.extend(path) | |
| 221 def __exit__(self2, _, __, ___): | |
| 222 self._lookup_path[:] = self._lookup_path[:-len(path)] | |
| 223 return scope() | |
| 224 | |
| 225 | |
| 68 class _JSCModel(object): | 226 class _JSCModel(object): |
| 69 '''Uses a Model from the JSON Schema Compiler and generates a dict that | 227 '''Uses a Model from the JSON Schema Compiler and generates a dict that |
| 70 a Handlebar template can use for a data source. | 228 a Handlebar template can use for a data source. |
| 71 ''' | 229 ''' |
| 72 | 230 |
| 73 def __init__(self, | 231 def __init__(self, |
| 74 namespace, | 232 namespace, |
| 75 availability_finder, | 233 availability_finder, |
| 76 json_cache, | 234 json_cache, |
| 77 template_cache, | 235 template_cache, |
| 78 features_bundle, | 236 features_bundle, |
| 79 event_byname_future): | 237 event_byname_future): |
| 80 self._availability = availability_finder.GetAPIAvailability(namespace.name) | 238 self._availability = availability_finder.GetAPIAvailability(namespace.name) |
| 239 self._current_node = _APINodeCursor(availability_finder, namespace.name) | |
| 81 self._api_availabilities = json_cache.GetFromFile( | 240 self._api_availabilities = json_cache.GetFromFile( |
| 82 posixpath.join(JSON_TEMPLATES, 'api_availabilities.json')) | 241 posixpath.join(JSON_TEMPLATES, 'api_availabilities.json')) |
| 83 self._intro_tables = json_cache.GetFromFile( | 242 self._intro_tables = json_cache.GetFromFile( |
| 84 posixpath.join(JSON_TEMPLATES, 'intro_tables.json')) | 243 posixpath.join(JSON_TEMPLATES, 'intro_tables.json')) |
| 85 self._api_features = features_bundle.GetAPIFeatures() | 244 self._api_features = features_bundle.GetAPIFeatures() |
| 86 self._template_cache = template_cache | 245 self._template_cache = template_cache |
| 87 self._event_byname_future = event_byname_future | 246 self._event_byname_future = event_byname_future |
| 88 self._namespace = namespace | 247 self._namespace = namespace |
| 89 | 248 |
| 90 def _GetLink(self, link): | 249 def _GetLink(self, link): |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 120 if not self._IsExperimental(): | 279 if not self._IsExperimental(): |
| 121 return { | 280 return { |
| 122 self._availability.channel_info.channel: True | 281 self._availability.channel_info.channel: True |
| 123 } | 282 } |
| 124 return None | 283 return None |
| 125 | 284 |
| 126 def _IsExperimental(self): | 285 def _IsExperimental(self): |
| 127 return self._namespace.name.startswith('experimental') | 286 return self._namespace.name.startswith('experimental') |
| 128 | 287 |
| 129 def _GenerateTypes(self, types): | 288 def _GenerateTypes(self, types): |
| 130 return [self._GenerateType(t) for t in types] | 289 with self._current_node.Descend('types'): |
| 290 return [self._GenerateType(t) for t in types] | |
| 131 | 291 |
| 132 def _GenerateType(self, type_): | 292 def _GenerateType(self, type_): |
| 133 type_dict = { | 293 with self._current_node.Descend(type_.simple_name): |
| 134 'name': type_.simple_name, | 294 type_dict = { |
| 135 'description': type_.description, | 295 'name': type_.simple_name, |
| 136 'properties': self._GenerateProperties(type_.properties), | 296 'description': type_.description, |
| 137 'functions': self._GenerateFunctions(type_.functions), | 297 'properties': self._GenerateProperties(type_.properties), |
| 138 'events': self._GenerateEvents(type_.events), | 298 'functions': self._GenerateFunctions(type_.functions), |
| 139 'id': _CreateId(type_, 'type') | 299 'events': self._GenerateEvents(type_.events), |
| 140 } | 300 'id': _CreateId(type_, 'type'), |
| 141 self._RenderTypeInformation(type_, type_dict) | 301 } |
| 142 return type_dict | 302 self._RenderTypeInformation(type_, type_dict) |
| 303 return type_dict | |
| 143 | 304 |
| 144 def _GenerateFunctions(self, functions): | 305 def _GenerateFunctions(self, functions): |
| 145 return [self._GenerateFunction(f) for f in functions.values()] | 306 with self._current_node.Descend('functions'): |
| 307 return [self._GenerateFunction(f) for f in functions.values()] | |
| 146 | 308 |
| 147 def _GenerateFunction(self, function): | 309 def _GenerateFunction(self, function): |
| 148 function_dict = { | 310 with self._current_node.Descend(function.simple_name): |
| 149 'name': function.simple_name, | 311 function_dict = { |
| 150 'description': function.description, | 312 'name': function.simple_name, |
| 151 'callback': self._GenerateCallback(function.callback), | 313 'description': function.description, |
| 152 'parameters': [], | 314 'callback': self._GenerateCallback(function.callback), |
| 153 'returns': None, | 315 'parameters': [], |
| 154 'id': _CreateId(function, 'method') | 316 'returns': None, |
| 155 } | 317 'id': _CreateId(function, 'method'), |
| 156 self._AddCommonProperties(function_dict, function) | 318 'availability': self._GetAvailabilityTemplate() |
| 157 if function.returns: | 319 } |
| 158 function_dict['returns'] = self._GenerateType(function.returns) | 320 self._AddCommonProperties(function_dict, function) |
| 159 for param in function.params: | 321 if function.returns: |
| 160 function_dict['parameters'].append(self._GenerateProperty(param)) | 322 function_dict['returns'] = self._GenerateType(function.returns) |
| 161 if function.callback is not None: | 323 for param in function.params: |
| 162 # Show the callback as an extra parameter. | 324 function_dict['parameters'].append(self._GenerateProperty(param)) |
| 163 function_dict['parameters'].append( | 325 if function.callback is not None: |
| 164 self._GenerateCallbackProperty(function.callback)) | 326 # Show the callback as an extra parameter. |
| 165 if len(function_dict['parameters']) > 0: | 327 function_dict['parameters'].append( |
| 166 function_dict['parameters'][-1]['last'] = True | 328 self._GenerateCallbackProperty(function.callback)) |
| 167 return function_dict | 329 if len(function_dict['parameters']) > 0: |
| 330 function_dict['parameters'][-1]['last'] = True | |
| 331 return function_dict | |
| 168 | 332 |
| 169 def _GenerateEvents(self, events): | 333 def _GenerateEvents(self, events): |
| 170 return [self._GenerateEvent(e) for e in events.values() | 334 with self._current_node.Descend('events'): |
| 171 if not e.supports_dom] | 335 return [self._GenerateEvent(e) for e in events.values() |
| 336 if not e.supports_dom] | |
| 172 | 337 |
| 173 def _GenerateDomEvents(self, events): | 338 def _GenerateDomEvents(self, events): |
| 174 return [self._GenerateEvent(e) for e in events.values() | 339 with self._current_node.Descend('events'): |
| 175 if e.supports_dom] | 340 return [self._GenerateEvent(e) for e in events.values() |
| 341 if e.supports_dom] | |
| 176 | 342 |
| 177 def _GenerateEvent(self, event): | 343 def _GenerateEvent(self, event): |
| 178 event_dict = { | 344 with self._current_node.Descend(event.simple_name): |
| 179 'name': event.simple_name, | 345 event_dict = { |
| 180 'description': event.description, | 346 'name': event.simple_name, |
| 181 'filters': [self._GenerateProperty(f) for f in event.filters], | 347 'description': event.description, |
| 182 'conditions': [self._GetLink(condition) | 348 'filters': [self._GenerateProperty(f) for f in event.filters], |
| 183 for condition in event.conditions], | 349 'conditions': [self._GetLink(condition) |
| 184 'actions': [self._GetLink(action) for action in event.actions], | 350 for condition in event.conditions], |
| 185 'supportsRules': event.supports_rules, | 351 'actions': [self._GetLink(action) for action in event.actions], |
| 186 'supportsListeners': event.supports_listeners, | 352 'supportsRules': event.supports_rules, |
| 187 'properties': [], | 353 'supportsListeners': event.supports_listeners, |
| 188 'id': _CreateId(event, 'event'), | 354 'properties': [], |
| 189 'byName': {}, | 355 'id': _CreateId(event, 'event'), |
| 190 } | 356 'byName': {}, |
| 191 self._AddCommonProperties(event_dict, event) | |
| 192 # Add the Event members to each event in this object. | |
| 193 if self._event_byname_future: | |
| 194 event_dict['byName'].update(self._event_byname_future.Get()) | |
| 195 # We need to create the method description for addListener based on the | |
| 196 # information stored in |event|. | |
| 197 if event.supports_listeners: | |
| 198 callback_object = model.Function(parent=event, | |
| 199 name='callback', | |
| 200 json={}, | |
| 201 namespace=event.parent, | |
| 202 origin='') | |
| 203 callback_object.params = event.params | |
| 204 if event.callback: | |
| 205 callback_object.callback = event.callback | |
| 206 callback_parameters = self._GenerateCallbackProperty(callback_object) | |
| 207 callback_parameters['last'] = True | |
| 208 event_dict['byName']['addListener'] = { | |
| 209 'name': 'addListener', | |
| 210 'callback': self._GenerateFunction(callback_object), | |
| 211 'parameters': [callback_parameters] | |
| 212 } | 357 } |
| 213 if event.supports_dom: | 358 self._AddCommonProperties(event_dict, event) |
| 214 # Treat params as properties of the custom Event object associated with | 359 # Add the Event members to each event in this object. |
| 215 # this DOM Event. | 360 if self._event_byname_future: |
| 216 event_dict['properties'] += [self._GenerateProperty(param) | 361 event_dict['byName'].update(self._event_byname_future.Get()) |
| 217 for param in event.params] | 362 # We need to create the method description for addListener based on the |
| 218 return event_dict | 363 # information stored in |event|. |
| 364 if event.supports_listeners: | |
| 365 callback_object = model.Function(parent=event, | |
| 366 name='callback', | |
| 367 json={}, | |
| 368 namespace=event.parent, | |
| 369 origin='') | |
| 370 callback_object.params = event.params | |
| 371 if event.callback: | |
| 372 callback_object.callback = event.callback | |
| 373 callback_parameters = self._GenerateCallbackProperty(callback_object) | |
| 374 callback_parameters['last'] = True | |
| 375 event_dict['byName']['addListener'] = { | |
| 376 'name': 'addListener', | |
| 377 'callback': self._GenerateFunction(callback_object), | |
| 378 'parameters': [callback_parameters] | |
| 379 } | |
| 380 if event.supports_dom: | |
| 381 # Treat params as properties of the custom Event object associated with | |
| 382 # this DOM Event. | |
| 383 event_dict['properties'] += [self._GenerateProperty(param) | |
| 384 for param in event.params] | |
| 385 return event_dict | |
| 219 | 386 |
| 220 def _GenerateCallback(self, callback): | 387 def _GenerateCallback(self, callback): |
| 221 if not callback: | 388 if not callback: |
| 222 return None | 389 return None |
| 223 callback_dict = { | 390 callback_dict = { |
| 224 'name': callback.simple_name, | 391 'name': callback.simple_name, |
| 225 'simple_type': {'simple_type': 'function'}, | 392 'simple_type': {'simple_type': 'function'}, |
| 226 'optional': callback.optional, | 393 'optional': callback.optional, |
| 227 'parameters': [] | 394 'parameters': [] |
| 228 } | 395 } |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 250 properties = type_.properties | 417 properties = type_.properties |
| 251 | 418 |
| 252 property_dict = { | 419 property_dict = { |
| 253 'name': property_.simple_name, | 420 'name': property_.simple_name, |
| 254 'optional': property_.optional, | 421 'optional': property_.optional, |
| 255 'description': property_.description, | 422 'description': property_.description, |
| 256 'properties': self._GenerateProperties(type_.properties), | 423 'properties': self._GenerateProperties(type_.properties), |
| 257 'functions': self._GenerateFunctions(type_.functions), | 424 'functions': self._GenerateFunctions(type_.functions), |
| 258 'parameters': [], | 425 'parameters': [], |
| 259 'returns': None, | 426 'returns': None, |
| 260 'id': _CreateId(property_, 'property') | 427 'id': _CreateId(property_, 'property'), |
| 261 } | 428 } |
| 262 self._AddCommonProperties(property_dict, property_) | 429 self._AddCommonProperties(property_dict, property_) |
| 263 | 430 |
| 264 if type_.property_type == model.PropertyType.FUNCTION: | 431 if type_.property_type == model.PropertyType.FUNCTION: |
| 265 function = type_.function | 432 function = type_.function |
| 266 for param in function.params: | 433 for param in function.params: |
| 267 property_dict['parameters'].append(self._GenerateProperty(param)) | 434 property_dict['parameters'].append(self._GenerateProperty(param)) |
| 268 if function.returns: | 435 if function.returns: |
| 269 property_dict['returns'] = self._GenerateType(function.returns) | 436 property_dict['returns'] = self._GenerateType(function.returns) |
| 270 | 437 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 329 # if they share the same 'title' attribute. | 496 # if they share the same 'title' attribute. |
| 330 row_titles = [row['title'] for row in intro_rows] | 497 row_titles = [row['title'] for row in intro_rows] |
| 331 for misc_row in self._GetMiscIntroRows(): | 498 for misc_row in self._GetMiscIntroRows(): |
| 332 if misc_row['title'] in row_titles: | 499 if misc_row['title'] in row_titles: |
| 333 intro_rows[row_titles.index(misc_row['title'])] = misc_row | 500 intro_rows[row_titles.index(misc_row['title'])] = misc_row |
| 334 else: | 501 else: |
| 335 intro_rows.append(misc_row) | 502 intro_rows.append(misc_row) |
| 336 | 503 |
| 337 return intro_rows | 504 return intro_rows |
| 338 | 505 |
| 506 def _GetAvailabilityTemplate(self, status=None, version=None, scheduled=None): | |
| 507 '''Returns an object that the templates use to display availability | |
| 508 information. | |
| 509 ''' | |
| 510 if status is None: | |
| 511 availability_info = self._current_node.GetAvailability() | |
| 512 if availability_info is None: | |
| 513 return None | |
| 514 status = availability_info.channel | |
| 515 version = availability_info.version | |
| 516 return { | |
| 517 'partial': self._template_cache.GetFromFile( | |
| 518 '%sintro_tables/%s_message.html' % (PRIVATE_TEMPLATES, status)).Get(), | |
| 519 'scheduled': scheduled, | |
| 520 'version': version | |
| 521 } | |
| 522 | |
| 339 def _GetIntroDescriptionRow(self): | 523 def _GetIntroDescriptionRow(self): |
| 340 ''' Generates the 'Description' row data for an API intro table. | 524 ''' Generates the 'Description' row data for an API intro table. |
| 341 ''' | 525 ''' |
| 342 return { | 526 return { |
| 343 'title': 'Description', | 527 'title': 'Description', |
| 344 'content': [ | 528 'content': [ |
| 345 { 'text': self._namespace.description } | 529 { 'text': self._namespace.description } |
| 346 ] | 530 ] |
| 347 } | 531 } |
| 348 | 532 |
| 349 def _GetIntroAvailabilityRow(self): | 533 def _GetIntroAvailabilityRow(self): |
| 350 ''' Generates the 'Availability' row data for an API intro table. | 534 ''' Generates the 'Availability' row data for an API intro table. |
| 351 ''' | 535 ''' |
| 352 if self._IsExperimental(): | 536 if self._IsExperimental(): |
| 353 status = 'experimental' | 537 status = 'experimental' |
| 354 version = None | 538 version = None |
| 355 scheduled = None | 539 scheduled = None |
| 356 else: | 540 else: |
| 357 status = self._availability.channel_info.channel | 541 status = self._availability.channel_info.channel |
| 358 version = self._availability.channel_info.version | 542 version = self._availability.channel_info.version |
| 359 scheduled = self._availability.scheduled | 543 scheduled = self._availability.scheduled |
| 360 return { | 544 return { |
| 361 'title': 'Availability', | 545 'title': 'Availability', |
| 362 'content': [{ | 546 'content': [ |
| 363 'partial': self._template_cache.GetFromFile( | 547 self._GetAvailabilityTemplate(status=status, |
| 364 posixpath.join(PRIVATE_TEMPLATES, | 548 version=version, |
| 365 'intro_tables', | 549 scheduled=scheduled) |
| 366 '%s_message.html' % status)).Get(), | 550 ] |
| 367 'version': version, | |
| 368 'scheduled': scheduled | |
| 369 }] | |
| 370 } | 551 } |
| 371 | 552 |
| 372 def _GetIntroDependencyRows(self): | 553 def _GetIntroDependencyRows(self): |
| 373 # Devtools aren't in _api_features. If we're dealing with devtools, bail. | 554 # Devtools aren't in _api_features. If we're dealing with devtools, bail. |
| 374 if 'devtools' in self._namespace.name: | 555 if 'devtools' in self._namespace.name: |
| 375 return [] | 556 return [] |
| 376 | 557 |
| 377 api_feature = self._api_features.Get().get(self._namespace.name) | 558 api_feature = self._api_features.Get().get(self._namespace.name) |
| 378 if not api_feature: | 559 if not api_feature: |
| 379 logging.error('"%s" not found in _api_features.json' % | 560 logging.error('"%s" not found in _api_features.json' % |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 535 getter = lambda: 0 | 716 getter = lambda: 0 |
| 536 getter.get = lambda api_name: self._GetImpl(platform, api_name).Get() | 717 getter.get = lambda api_name: self._GetImpl(platform, api_name).Get() |
| 537 return getter | 718 return getter |
| 538 | 719 |
| 539 def Cron(self): | 720 def Cron(self): |
| 540 futures = [] | 721 futures = [] |
| 541 for platform in GetPlatforms(): | 722 for platform in GetPlatforms(): |
| 542 futures += [self._GetImpl(platform, name) | 723 futures += [self._GetImpl(platform, name) |
| 543 for name in self._platform_bundle.GetAPIModels(platform).GetNames()] | 724 for name in self._platform_bundle.GetAPIModels(platform).GetNames()] |
| 544 return Collect(futures, except_pass=FileNotFoundError) | 725 return Collect(futures, except_pass=FileNotFoundError) |
| OLD | NEW |