Index: chrome/common/extensions/docs/server2/api_data_source.py |
=================================================================== |
--- chrome/common/extensions/docs/server2/api_data_source.py (revision 200185) |
+++ chrome/common/extensions/docs/server2/api_data_source.py (working copy) |
@@ -5,6 +5,7 @@ |
import copy |
import logging |
import os |
+from collections import defaultdict, Mapping |
import compiled_file_system as compiled_fs |
from file_system import FileNotFoundError |
@@ -38,6 +39,66 @@ |
item.remove(i) |
return False |
+def _DetectInlineableTypes(schema): |
+ """Look for documents that are only referenced once and mark them as inline. |
+ Actual inlining is done by _InlineDocs. |
+ """ |
+ if not schema.get('types'): |
+ return |
+ |
+ banned = frozenset(('value', 'choices', 'items', 'returns')) |
+ refcounts = defaultdict(int) |
+ # Use an explicit stack instead of recursion. |
+ stack = [schema] |
+ |
+ while stack: |
+ node = stack.pop() |
+ if isinstance(node, list): |
+ stack.extend(node) |
+ elif isinstance(node, Mapping): |
+ if '$ref' in node: |
+ refcounts[node['$ref']] += 1 |
+ stack.extend(v for k, v in node.iteritems() if k not in banned) |
+ |
+ for type_ in schema['types']: |
+ if not 'enum' in type_: |
+ if refcounts[type_['id']] == 1: |
+ type_['inline_doc'] = True |
+ |
+def _InlineDocs(schema): |
+ """Replace '$ref's that refer to inline_docs with the json for those docs. |
+ """ |
+ types = schema.get('types') |
+ if types is None: |
+ return |
+ |
+ inline_docs = {} |
+ types_without_inline_doc = [] |
+ |
+ # Gather the types with inline_doc. |
+ for type_ in types: |
+ if type_.get('inline_doc'): |
+ inline_docs[type_['id']] = type_ |
+ for k in ('description', 'id', 'inline_doc'): |
+ type_.pop(k, None) |
+ else: |
+ types_without_inline_doc.append(type_) |
+ schema['types'] = types_without_inline_doc |
+ |
+ def apply_inline(node): |
+ if isinstance(node, list): |
+ for i in node: |
+ apply_inline(i) |
+ elif isinstance(node, Mapping): |
+ ref = node.get('$ref') |
+ if ref and ref in inline_docs: |
+ node.update(inline_docs[ref]) |
+ del node['$ref'] |
+ for k, v in node.iteritems(): |
+ apply_inline(v) |
+ |
+ apply_inline(schema) |
+ |
def _CreateId(node, prefix): |
if node.parent is not None and not isinstance(node.parent, model.Namespace): |
return '-'.join([prefix, node.parent.simple_name, node.simple_name]) |
@@ -53,13 +114,16 @@ |
"""Uses a Model from the JSON Schema Compiler and generates a dict that |
a Handlebar template can use for a data source. |
""" |
- def __init__(self, json, ref_resolver, disable_refs): |
+ def __init__(self, json, ref_resolver, disable_refs, idl=False): |
self._ref_resolver = ref_resolver |
self._disable_refs = disable_refs |
clean_json = copy.deepcopy(json) |
if _RemoveNoDocs(clean_json): |
self._namespace = None |
else: |
+ if idl: |
+ _DetectInlineableTypes(clean_json) |
+ _InlineDocs(clean_json) |
self._namespace = model.Namespace(clean_json, clean_json['namespace']) |
def _FormatDescription(self, description): |
@@ -356,7 +420,8 @@ |
return _JSCModel( |
idl_schema.IDLSchema(idl).process()[0], |
self._ref_resolver_factory.Create() if not disable_refs else None, |
- disable_refs).ToDict() |
+ disable_refs, |
+ idl=True).ToDict() |
def _GetIDLNames(self, base_dir, apis): |
return [ |