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

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: 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
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 882c0a66b51072fe9914da7954293c1f902d04a9..df9c0f0b41dce9755fb0259a3976a79187d6b021 100644
--- a/chrome/common/extensions/docs/server2/api_data_source.py
+++ b/chrome/common/extensions/docs/server2/api_data_source.py
@@ -65,6 +65,123 @@ 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']
+ '''
not at google - send to devlin 2014/07/01 16:40:57 nit: blank line here
+ def __init__(self, availability_finder, namespace_name):
+ # The cursor begins life at the root.
+ self._lookup_path = [namespace_name]
not at google - send to devlin 2014/07/01 16:40:57 rather than doing this could you include |namespac
+ 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.).
not at google - send to devlin 2014/07/01 16:40:57 could you define the set of acceptable categories
+ # 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.).
not at google - send to devlin 2014/07/01 16:40:57 ditto
+ # 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
not at google - send to devlin 2014/07/01 16:40:58 I'd rather you always restored this, and in a try.
+ # 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:
not at google - send to devlin 2014/07/01 16:40:57 so if there's an 'events' there *must* be a 'callb
+ lookup_path_copy = copy(self._lookup_path)
+ self._lookup_path.remove('callback')
+ node_availability = self._LookupNodeAvailability()
+ self._lookup_path = lookup_path_copy
not at google - send to devlin 2014/07/01 16:40:57 you should be able to do this without copy'ing; us
+ return node_availability
+ return None
+
+ def GetAvailability(self):
+ '''Returns availability information for this node.
+ '''
+ 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 Descend(self, *path):
+ '''Moves down the APISchemaGraph, following |path|.
+ '''
+ class scope(object):
+ def __enter__(self2):
+ self._lookup_path.extend(path)
not at google - send to devlin 2014/07/01 16:40:58 actually this is fine
+ def __exit__(self2, _, __, ___):
+ self._lookup_path = self._lookup_path[:-len(path)]
not at google - send to devlin 2014/07/01 16:40:57 nit: slightly better to be consistent and mutate |
+ return scope()
+
+
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.
@@ -78,6 +195,7 @@ class _JSCModel(object):
features_bundle,
event_byname_future):
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,95 +245,103 @@ class _JSCModel(object):
return self._namespace.name.startswith('experimental')
def _GenerateTypes(self, types):
- return [self._GenerateType(t) for t in types]
+ with self._current_node.Descend('types'):
not at google - send to devlin 2014/07/01 16:40:58 nice!
+ return [self._GenerateType(t) for t in types]
def _GenerateType(self, type_):
- 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')
- }
- self._RenderTypeInformation(type_, type_dict)
- return type_dict
+ with self._current_node.Descend(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'),
+ }
+ self._RenderTypeInformation(type_, type_dict)
+ return type_dict
def _GenerateFunctions(self, functions):
- return [self._GenerateFunction(f) for f in functions.values()]
+ with self._current_node.Descend('functions'):
+ return [self._GenerateFunction(f) for f in functions.values()]
def _GenerateFunction(self, function):
- function_dict = {
- 'name': function.simple_name,
- 'description': function.description,
- 'callback': self._GenerateCallback(function.callback),
- 'parameters': [],
- 'returns': None,
- 'id': _CreateId(function, 'method')
- }
- self._AddCommonProperties(function_dict, function)
- if function.returns:
- function_dict['returns'] = self._GenerateType(function.returns)
- for param in function.params:
- function_dict['parameters'].append(self._GenerateProperty(param))
- if function.callback is not None:
- # Show the callback as an extra parameter.
- function_dict['parameters'].append(
- self._GenerateCallbackProperty(function.callback))
- if len(function_dict['parameters']) > 0:
- function_dict['parameters'][-1]['last'] = True
- return function_dict
+ with self._current_node.Descend(function.simple_name):
+ function_dict = {
+ 'name': function.simple_name,
+ 'description': function.description,
+ 'callback': self._GenerateCallback(function.callback),
+ 'parameters': [],
+ 'returns': None,
+ 'id': _CreateId(function, 'method'),
+ 'availability': self._GetAvailabilityTemplate()
+ }
+ self._AddCommonProperties(function_dict, function)
+ if function.returns:
+ function_dict['returns'] = self._GenerateType(function.returns)
+ for param in function.params:
+ function_dict['parameters'].append(self._GenerateProperty(param))
+ if function.callback is not None:
+ # Show the callback as an extra parameter.
+ function_dict['parameters'].append(
+ self._GenerateCallbackProperty(function.callback))
+ if len(function_dict['parameters']) > 0:
+ function_dict['parameters'][-1]['last'] = True
+ return function_dict
def _GenerateEvents(self, events):
- return [self._GenerateEvent(e) for e in events.values()
- if not e.supports_dom]
+ with self._current_node.Descend('events'):
+ return [self._GenerateEvent(e) for e in events.values()
+ if not e.supports_dom]
def _GenerateDomEvents(self, events):
- return [self._GenerateEvent(e) for e in events.values()
- if e.supports_dom]
+ with self._current_node.Descend('events'):
+ return [self._GenerateEvent(e) for e in events.values()
+ if e.supports_dom]
def _GenerateEvent(self, event):
- event_dict = {
- 'name': event.simple_name,
- 'description': event.description,
- 'filters': [self._GenerateProperty(f) for f in event.filters],
- 'conditions': [self._GetLink(condition)
- for condition in event.conditions],
- 'actions': [self._GetLink(action) for action in event.actions],
- 'supportsRules': event.supports_rules,
- 'supportsListeners': event.supports_listeners,
- 'properties': [],
- 'id': _CreateId(event, 'event'),
- 'byName': {},
- }
- self._AddCommonProperties(event_dict, event)
- # Add the Event members to each event in this object.
- if self._event_byname_future:
- event_dict['byName'].update(self._event_byname_future.Get())
- # We need to create the method description for addListener based on the
- # information stored in |event|.
- if event.supports_listeners:
- callback_object = model.Function(parent=event,
- name='callback',
- json={},
- namespace=event.parent,
- origin='')
- callback_object.params = event.params
- if event.callback:
- callback_object.callback = event.callback
- callback_parameters = self._GenerateCallbackProperty(callback_object)
- callback_parameters['last'] = True
- event_dict['byName']['addListener'] = {
- 'name': 'addListener',
- 'callback': self._GenerateFunction(callback_object),
- 'parameters': [callback_parameters]
+ with self._current_node.Descend(event.simple_name):
+ event_dict = {
+ 'name': event.simple_name,
+ 'description': event.description,
+ 'filters': [self._GenerateProperty(f) for f in event.filters],
+ 'conditions': [self._GetLink(condition)
+ for condition in event.conditions],
+ 'actions': [self._GetLink(action) for action in event.actions],
+ 'supportsRules': event.supports_rules,
+ 'supportsListeners': event.supports_listeners,
+ 'properties': [],
+ 'id': _CreateId(event, 'event'),
+ 'byName': {},
}
- if event.supports_dom:
- # Treat params as properties of the custom Event object associated with
- # this DOM Event.
- event_dict['properties'] += [self._GenerateProperty(param)
- for param in event.params]
- return event_dict
+ self._AddCommonProperties(event_dict, event)
+ # Add the Event members to each event in this object.
+ if self._event_byname_future:
+ event_dict['byName'].update(self._event_byname_future.Get())
+ # We need to create the method description for addListener based on the
+ # information stored in |event|.
+ if event.supports_listeners:
+ callback_object = model.Function(parent=event,
+ name='callback',
+ json={},
+ namespace=event.parent,
+ origin='')
+ callback_object.params = event.params
+ if event.callback:
+ callback_object.callback = event.callback
+ callback_parameters = self._GenerateCallbackProperty(callback_object)
+ callback_parameters['last'] = True
+ event_dict['byName']['addListener'] = {
+ 'name': 'addListener',
+ 'callback': self._GenerateFunction(callback_object),
+ 'parameters': [callback_parameters]
+ }
+ if event.supports_dom:
+ # Treat params as properties of the custom Event object associated with
+ # this DOM Event.
+ event_dict['properties'] += [self._GenerateProperty(param)
+ for param in event.params]
+ return event_dict
def _GenerateCallback(self, callback):
if not callback:
@@ -257,7 +383,7 @@ class _JSCModel(object):
'functions': self._GenerateFunctions(type_.functions),
'parameters': [],
'returns': None,
- 'id': _CreateId(property_, 'property')
+ 'id': _CreateId(property_, 'property'),
}
self._AddCommonProperties(property_dict, property_)
@@ -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(
not at google - send to devlin 2014/07/01 16:40:57 nit: indent -=2 on these
+ '%sintro_tables/%s_message.html' % (PRIVATE_TEMPLATES, status)).Get(),
not at google - send to devlin 2014/07/01 16:40:58 nit: indent += 2 (relative to the previous line) h
+ 'version': version,
+ 'scheduled': scheduled
not at google - send to devlin 2014/07/01 16:40:58 nit: I'm going to try making these objects alphabe
+ }
+
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):

Powered by Google App Engine
This is Rietveld 408576698