Chromium Code Reviews| Index: chrome/common/extensions/docs/server2/api_data_source.py |
| diff --git a/chrome/common/extensions/docs/server2/api_data_source.py b/chrome/common/extensions/docs/server2/api_data_source.py |
| index f81dbf2eee63e7b7100b0d15605bed44cc994e22..166faf0c89d3843bb38483ce5febd186adf8b499 100644 |
| --- a/chrome/common/extensions/docs/server2/api_data_source.py |
| +++ b/chrome/common/extensions/docs/server2/api_data_source.py |
| @@ -65,6 +65,127 @@ def _GetEventByNameFromEvents(events): |
| return _GetByNameDict(event_list[0]) |
| +class _APINodeCursor(object): |
|
not at google - send to devlin
2014/06/28 00:21:02
use of this class would be nicer if you used the w
|
| + '''An abstract representation of a node in an APISchemaGraph. |
| + The current position in the graph is represented by a path into the |
| + underlying dictionary. So if the APISchemaGraph is: |
| + |
| + { |
| + 'tabs': { |
| + 'types': { |
| + 'Tab': { |
| + 'properties': { |
| + 'url': { |
| + ... |
| + } |
| + } |
| + } |
| + } |
| + } |
| + } |
| + |
| + then the 'url' property would be represented by: |
| + |
| + ['tabs', 'types', 'Tab', 'properties', 'url'] |
| + ''' |
| + def __init__(self, availability_finder, namespace_name): |
| + # The cursor begins life at the root. |
| + self._lookup_path = [namespace_name] |
| + self._node_availabilities = availability_finder.GetAPINodeAvailability( |
| + namespace_name) |
| + self._namespace_name = namespace_name |
| + |
| + def _GetParentPath(self): |
| + '''Returns the path pointing to this node's parent. |
| + ''' |
| + assert len(self._lookup_path) > 2, \ |
| + 'Tried to look up parent for the top-level node.' |
| + |
| + # lookup_path[-1] is the name of the current node. |
| + # lookup_path[-2] is this node's category (e.g. types, events, etc.). |
| + # Thus, the parent node is described by lookup_path[:-2]. |
| + return self._lookup_path[:-2] |
| + |
| + def _LookupNodeAvailability(self): |
| + '''Returns the ChannelInfo object for this node. |
| + ''' |
| + return self._node_availabilities.Lookup(*self._lookup_path).annotation |
| + |
| + def _LookupParentNodeAvailability(self): |
| + '''Returns the ChannelInfo object for this node's parent. |
| + ''' |
| + return self._node_availabilities.Lookup(*self._GetParentPath()).annotation |
| + |
| + def _CheckNamespacePrefix(self): |
| + '''API schemas may prepend the namespace name to top-level types |
| + (e.g. declarativeWebRequest > types > declarativeWebRequest.IgnoreRules), |
| + but just the base name (here, 'IgnoreRules') will be in the |lookup_path|. |
| + Try creating an alternate |lookup_path| by adding the namespace name. |
| + ''' |
| + # lookup_path[0] is always the API namespace, and |
| + # lookup_path[1] is always the node category (e.g. types, functions, etc.). |
| + # Thus, lookup_path[2] is always the top-level node name. |
| + base_name = self._lookup_path[2] |
| + self._lookup_path[2] = '%s.%s' % (self._namespace_name, base_name) |
| + node_availability = self._LookupNodeAvailability() |
| + if node_availability is not None: |
| + return node_availability |
| + # We want to maintain a working lookup_path, so only restore it |
| + # if modifying the lookup_path did not work. |
| + self._lookup_path[2] = base_name |
| + return None |
| + |
| + def _CheckEventCallback(self): |
| + '''Within API schemas, an event has a list of 'properties' that the event's |
| + callback expects. The callback itself is not explicitly represented in the |
| + schema. However, when creating an event node in _JSCModel, a callback node |
| + is generated and acts as the parent for the event's properties. |
| + Modify |lookup_path| to check the original schema format. |
| + ''' |
| + if 'events' in self._lookup_path and 'callback' in self._lookup_path: |
| + lookup_path_copy = copy(self._lookup_path) |
| + self._lookup_path.remove('callback') |
| + node_availability = self._LookupNodeAvailability() |
| + self._lookup_path = lookup_path_copy |
| + return node_availability |
| + return None |
| + |
| + def GetAvailability(self): |
| + '''Returns availability information for this node. |
| + ''' |
| + if self._lookup_path[0] != self._namespace_name: |
| + # |lookup_path| won't be lookup up if it doesn't start with the API name. |
| + return None |
| + |
| + for lookup in (self._LookupNodeAvailability, |
| + self._CheckEventCallback, |
| + self._CheckNamespacePrefix): |
| + node_availability = lookup() |
| + if node_availability is not None: |
| + break |
| + |
| + if node_availability is None: |
| + logging.warning('No availability found for: %s' % ' > '.join( |
| + self._lookup_path)) |
| + return None |
| + |
| + # Only render this node's availability if it differs from the parent |
| + # node's availability. |
| + if node_availability == self._LookupParentNodeAvailability(): |
| + return None |
| + return node_availability |
| + |
| + def DescendTo(self, *path): |
| + '''Moves down the APISchemaGraph, following |path|. |
| + ''' |
| + self._lookup_path.extend(path) |
| + |
| + def Ascend(self): |
| + '''Moves up one node. |
| + ''' |
| + self._lookup_path = self._lookup_path[:-1] |
| + |
| + |
| class _JSCModel(object): |
| '''Uses a Model from the JSON Schema Compiler and generates a dict that |
| a Handlebar template can use for a data source. |
| @@ -72,12 +193,13 @@ class _JSCModel(object): |
| def __init__(self, |
| namespace, |
| - availability, |
| + availability_finder, |
| json_cache, |
| template_cache, |
| features_bundle, |
| event_byname_future): |
| - self._availability = availability |
| + self._availability = availability_finder.GetAPIAvailability(namespace.name) |
| + self._current_node = _APINodeCursor(availability_finder, namespace.name) |
| self._api_availabilities = json_cache.GetFromFile( |
| posixpath.join(JSON_TEMPLATES, 'api_availabilities.json')) |
| self._intro_tables = json_cache.GetFromFile( |
| @@ -127,31 +249,41 @@ class _JSCModel(object): |
| return self._namespace.name.startswith('experimental') |
| def _GenerateTypes(self, types): |
| - return [self._GenerateType(t) for t in types] |
| + self._current_node.DescendTo('types') |
| + types_ = [self._GenerateType(t) for t in types] |
| + self._current_node.Ascend() |
| + return types_ |
| def _GenerateType(self, type_): |
| + self._current_node.DescendTo(type_.simple_name) |
| type_dict = { |
| 'name': type_.simple_name, |
| 'description': type_.description, |
| 'properties': self._GenerateProperties(type_.properties), |
| 'functions': self._GenerateFunctions(type_.functions), |
| 'events': self._GenerateEvents(type_.events), |
| - 'id': _CreateId(type_, 'type') |
| + 'id': _CreateId(type_, 'type'), |
| } |
| self._RenderTypeInformation(type_, type_dict) |
| + self._current_node.Ascend() |
| return type_dict |
| def _GenerateFunctions(self, functions): |
| - return [self._GenerateFunction(f) for f in functions.values()] |
| + self._current_node.DescendTo('functions') |
| + fns = [self._GenerateFunction(f) for f in functions.values()] |
| + self._current_node.Ascend() |
| + return fns |
| def _GenerateFunction(self, function): |
| + self._current_node.DescendTo(function.simple_name) |
| function_dict = { |
| 'name': function.simple_name, |
| 'description': function.description, |
| 'callback': self._GenerateCallback(function.callback), |
| 'parameters': [], |
| 'returns': None, |
| - 'id': _CreateId(function, 'method') |
| + 'id': _CreateId(function, 'method'), |
| + 'availability': self._GetAvailabilityTemplate() |
| } |
| self._AddCommonProperties(function_dict, function) |
| if function.returns: |
| @@ -164,17 +296,25 @@ class _JSCModel(object): |
| self._GenerateCallbackProperty(function.callback)) |
| if len(function_dict['parameters']) > 0: |
| function_dict['parameters'][-1]['last'] = True |
| + self._current_node.Ascend() |
| return function_dict |
| def _GenerateEvents(self, events): |
| - return [self._GenerateEvent(e) for e in events.values() |
| - if not e.supports_dom] |
| + self._current_node.DescendTo('events') |
| + events_ = [self._GenerateEvent(e) for e in events.values() |
| + if not e.supports_dom] |
| + self._current_node.Ascend() |
| + return events_ |
| def _GenerateDomEvents(self, events): |
| - return [self._GenerateEvent(e) for e in events.values() |
| - if e.supports_dom] |
| + self._current_node.DescendTo('events') |
| + events_ = [self._GenerateEvent(e) for e in events.values() |
| + if e.supports_dom] |
| + self._current_node.Ascend() |
| + return events_ |
| def _GenerateEvent(self, event): |
| + self._current_node.DescendTo(event.simple_name) |
| event_dict = { |
| 'name': event.simple_name, |
| 'description': event.description, |
| @@ -215,6 +355,7 @@ class _JSCModel(object): |
| # this DOM Event. |
| event_dict['properties'] += [self._GenerateProperty(param) |
| for param in event.params] |
| + self._current_node.Ascend() |
| return event_dict |
| def _GenerateCallback(self, callback): |
| @@ -336,6 +477,23 @@ class _JSCModel(object): |
| return intro_rows |
| + def _GetAvailabilityTemplate(self, status=None, version=None, scheduled=None): |
| + '''Returns an object that the templates use to display availability |
| + information. |
| + ''' |
| + if status is None: |
| + availability_info = self._current_node.GetAvailability() |
| + if availability_info is None: |
| + return None |
| + status = availability_info.channel |
| + version = availability_info.version |
| + return { |
| + 'partial': self._template_cache.GetFromFile( |
| + '%sintro_tables/%s_message.html' % (PRIVATE_TEMPLATES, status)).Get(), |
| + 'version': version, |
| + 'scheduled': scheduled |
| + } |
| + |
| def _GetIntroDescriptionRow(self): |
| ''' Generates the 'Description' row data for an API intro table. |
| ''' |
| @@ -359,14 +517,11 @@ class _JSCModel(object): |
| scheduled = self._availability.scheduled |
| return { |
| 'title': 'Availability', |
| - 'content': [{ |
| - 'partial': self._template_cache.GetFromFile( |
| - posixpath.join(PRIVATE_TEMPLATES, |
| - 'intro_tables', |
| - '%s_message.html' % status)).Get(), |
| - 'version': version, |
| - 'scheduled': scheduled |
| - }] |
| + 'content': [ |
| + self._GetAvailabilityTemplate(status=status, |
| + version=version, |
| + scheduled=scheduled) |
| + ] |
| } |
| def _GetIntroDependencyRows(self): |
| @@ -506,8 +661,7 @@ class APIDataSource(DataSource): |
| if jsc_model is None: |
| jsc_model = _JSCModel( |
| model_future.Get(), |
| - self._platform_bundle.GetAvailabilityFinder( |
| - platform).GetAPIAvailability(api_name), |
| + self._platform_bundle.GetAvailabilityFinder(platform), |
| self._json_cache, |
| self._template_cache, |
| self._platform_bundle.GetFeaturesBundle(platform), |