Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6345)

Unified Diff: chrome/common/extensions/docs/server2/api_data_source.py

Issue 354073004: Docserver: Add template support for object level availability (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Make abstractions Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | chrome/common/extensions/docs/server2/api_data_source_test.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..dcb445ae397e78413103c5fd6f932526569ea285 100644
--- a/chrome/common/extensions/docs/server2/api_data_source.py
+++ b/chrome/common/extensions/docs/server2/api_data_source.py
@@ -65,6 +65,124 @@ def _GetEventByNameFromEvents(events):
return _GetByNameDict(event_list[0])
+class _APINodeCursor(object):
+ '''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:
+ self._lookup_path.remove('callback')
ahernandez 2014/06/27 03:00:01 I'm not sure if this should be restored or not.
+ return self._LookupNodeAvailability()
+ 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 to the parent node.
+ '''
+ self._lookup_path = self._GetParentPath()
+
+
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 +190,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(
@@ -126,18 +245,23 @@ class _JSCModel(object):
def _IsExperimental(self):
return self._namespace.name.startswith('experimental')
- def _GenerateTypes(self, types):
- return [self._GenerateType(t) for t in types]
+ def _GenerateTypes(self, types, no_gen=False):
+ return [self._GenerateType(t, no_gen=no_gen) for t in types]
- def _GenerateType(self, type_):
+ def _GenerateType(self, type_, no_gen=False):
+ '''If |no_gen| is True, don't generate availability info.
+ '''
+ self._current_node.DescendTo('types', 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'),
+ 'availability': None if no_gen else self._GetAvailabilityTemplate()
}
+ self._current_node.Ascend()
ahernandez 2014/06/27 03:00:01 I'm not sure if the whole purpose of the APINodeCu
self._RenderTypeInformation(type_, type_dict)
return type_dict
@@ -155,7 +279,8 @@ class _JSCModel(object):
}
self._AddCommonProperties(function_dict, function)
if function.returns:
- function_dict['returns'] = self._GenerateType(function.returns)
+ function_dict['returns'] = self._GenerateType(function.returns,
+ no_gen=True)
ahernandez 2014/06/27 03:00:01 I think I now understand what the deal with the bl
for param in function.params:
function_dict['parameters'].append(self._GenerateProperty(param))
if function.callback is not None:
@@ -266,7 +391,8 @@ class _JSCModel(object):
for param in function.params:
property_dict['parameters'].append(self._GenerateProperty(param))
if function.returns:
- property_dict['returns'] = self._GenerateType(function.returns)
+ property_dict['returns'] = self._GenerateType(function.returns,
+ no_gen=True)
value = property_.value
if value is not None:
@@ -296,7 +422,7 @@ class _JSCModel(object):
def _RenderTypeInformation(self, type_, dst_dict):
dst_dict['is_object'] = type_.property_type == model.PropertyType.OBJECT
if type_.property_type == model.PropertyType.CHOICES:
- dst_dict['choices'] = self._GenerateTypes(type_.choices)
+ dst_dict['choices'] = self._GenerateTypes(type_.choices, no_gen=True)
# We keep track of which == last for knowing when to add "or" between
# choices in templates.
if len(dst_dict['choices']) > 0:
@@ -304,7 +430,7 @@ class _JSCModel(object):
elif type_.property_type == model.PropertyType.REF:
dst_dict['link'] = self._GetLink(type_.ref_type)
elif type_.property_type == model.PropertyType.ARRAY:
- dst_dict['array'] = self._GenerateType(type_.item_type)
+ dst_dict['array'] = self._GenerateType(type_.item_type, no_gen=True)
elif type_.property_type == model.PropertyType.ENUM:
dst_dict['enum_values'] = [
{'name': value.name, 'description': value.description}
@@ -336,6 +462,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 +502,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 +646,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),
« no previous file with comments | « no previous file | chrome/common/extensions/docs/server2/api_data_source_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698