Index: chrome/common/extensions/docs/server2/manifest_data_source.py |
diff --git a/chrome/common/extensions/docs/server2/manifest_data_source.py b/chrome/common/extensions/docs/server2/manifest_data_source.py |
index d0c2c15208be535c59f6a4a4ce50b089750a6c60..898352f6d3addce1ac0e48f30fd5702a193e4df4 100644 |
--- a/chrome/common/extensions/docs/server2/manifest_data_source.py |
+++ b/chrome/common/extensions/docs/server2/manifest_data_source.py |
@@ -2,14 +2,107 @@ |
# Use of this source code is governed by a BSD-style license that can be |
# found in the LICENSE file. |
-from copy import deepcopy |
-from operator import itemgetter |
+import json |
-from third_party.json_schema_compiler.json_parse import OrderedDict, Parse |
+import features_utility as features |
+from third_party.json_schema_compiler.json_parse import Parse |
+ |
+def _ListifyAndSortDocs(features, app_name): |
+ '''Convert a |feautres| dictionary, and all 'children' dictionaries, into |
+ lists recursively. Sort lists first by 'level' then by name. |
+ ''' |
+ def sort_key(item): |
+ '''Key function to sort items primarily by level (according to index into |
+ levels) then subsort by name. |
+ ''' |
+ levels = ('required', 'recommended', 'only_one', 'optional') |
+ |
+ return (levels.index(item.get('level', 'optional')), item['name']) |
+ |
+ def convert_and_sort(features): |
+ for key, value in features.items(): |
+ if 'example' in value: |
+ value['has_example'] = True |
+ example = json.dumps(value['example']) |
+ if example == '{}': |
+ value['example'] = '{...}' |
+ elif example == '[]': |
+ value['example'] = '[...]' |
+ else: |
+ value['example'] = example |
+ |
+ if 'children' in value: |
+ features[key]['children'] = convert_and_sort(value['children']) |
+ |
+ return sorted(features.values(), key=sort_key) |
+ |
+ name = features['name'] |
+ name['example'] = name['example'].replace('{{title}}', app_name) |
+ |
+ return convert_and_sort(features) |
+ |
+def _AddLevelAnnotations(features): |
+ '''Add level annotations to |features|. |features| and children lists must be |
+ sorted by 'level'. Annotations are added to the first item in a group of |
+ features of the same 'level'. |
+ |
+ The last item in a list has 'is_last' set to True. |
+ ''' |
+ annotations = { |
+ 'required': 'Required', |
+ 'recommended': 'Recommended', |
+ 'only_one': 'Pick one (or none)', |
+ 'optional': 'Optional' |
+ } |
+ |
+ def add_annotation(item, annotation): |
+ if not 'annotations' in item: |
+ item['annotations'] = [] |
+ item['annotations'].insert(0, annotation) |
+ |
+ def annotate(parent_level, features): |
+ current_level = parent_level |
+ for item in features: |
+ level = item.get('level', 'optional') |
+ if level != current_level: |
+ add_annotation(item, annotations[level]) |
+ current_level = level |
+ if 'children' in item: |
+ annotate(level, item['children']) |
+ if features: |
+ features[-1]['is_last'] = True |
+ |
+ annotate('required', features) |
+ return features |
+ |
+def _RestructureChildren(features): |
+ '''Features whose names are of the form 'parent.child' are moved to be part |
+ of the 'parent' dictionary under the key 'children'. Names are changed to |
+ the 'child' section of the original name. Applied recursively so that |
+ children can have children. |
+ ''' |
+ def add_child(features, parent, child_name, value): |
+ value['name'] = child_name |
+ if not 'children' in features[parent]: |
+ features[parent]['children'] = {} |
+ features[parent]['children'][child_name] = value |
+ |
+ def insert_children(features): |
+ for name in features.keys(): |
+ if '.' in name: |
+ value = features.pop(name) |
+ parent, child_name = name.split('.', 1) |
+ add_child(features, parent, child_name, value) |
+ |
+ for value in features.values(): |
+ if 'children' in value: |
+ insert_children(value['children']) |
+ |
+ insert_children(features) |
+ return features |
class ManifestDataSource(object): |
- '''Provides a template with access to manifest properties specific to apps or |
- extensions. |
+ '''Provides access to the properties in manifest features. |
''' |
def __init__(self, |
compiled_fs_factory, |
@@ -22,68 +115,37 @@ class ManifestDataSource(object): |
self._cache = compiled_fs_factory.Create( |
self._CreateManifestData, ManifestDataSource) |
- def _ApplyAppsTransformations(self, manifest): |
- manifest['required'][0]['example'] = 'Application' |
- manifest['optional'][-1]['is_last'] = True |
+ def GetFeatures(self): |
+ '''Returns a dictionary of the contents of |_features_path| merged with |
+ |_manifest_path|. |
+ ''' |
+ manifest_json = Parse(self._file_system.ReadSingle(self._manifest_path)) |
+ manifest_features = FeaturesModel.FromJson( |
+ Parse(self._file_system.ReadSingle(self._features_path))) |
+ |
+ return manifest_features.MergeWith(manifest_json) |
- def _ApplyExtensionsTransformations(self, manifest): |
- manifest['optional'][-1]['is_last'] = True |
def _CreateManifestData(self, _, content): |
- '''Take the contents of |_manifest_path| and create apps and extensions |
- versions of a manifest example based on the contents of |_features_path|. |
+ '''Combine the contents of |_manifest_path| and |_features_path| and filter |
+ the results into lists specific to apps or extensions for templates. Marks |
+ up features with annotations. |
''' |
- def create_manifest_dict(): |
- manifest_dict = OrderedDict() |
- for category in ('required', 'only_one', 'recommended', 'optional'): |
- manifest_dict[category] = [] |
- return manifest_dict |
- |
- apps = create_manifest_dict() |
- extensions = create_manifest_dict() |
- |
- manifest_json = Parse(content) |
- features_json = Parse(self._file_system.ReadSingle( |
- self._features_path)) |
- |
- def add_property(feature, manifest_key, category): |
- '''If |feature|, from features_json, has the correct extension_types, add |
- |manifest_key| to either apps or extensions. |
- ''' |
- added = False |
- extension_types = feature['extension_types'] |
- if extension_types == 'all' or 'platform_app' in extension_types: |
- apps[category].append(deepcopy(manifest_key)) |
- added = True |
- if extension_types == 'all' or 'extension' in extension_types: |
- extensions[category].append(deepcopy(manifest_key)) |
- added = True |
- return added |
- |
- # Property types are: required, only_one, recommended, and optional. |
- for category in manifest_json: |
- for manifest_key in manifest_json[category]: |
- # If a property is in manifest.json but not _manifest_features, this |
- # will cause an error. |
- feature = features_json[manifest_key['name']] |
- if add_property(feature, manifest_key, category): |
- del features_json[manifest_key['name']] |
- |
- # All of the properties left in features_json are assumed to be optional. |
- for feature in features_json.keys(): |
- item = features_json[feature] |
- # Handles instances where a features entry is a union with a whitelist. |
- if isinstance(item, list): |
- item = item[0] |
- add_property(item, {'name': feature}, 'optional') |
- |
- apps['optional'].sort(key=itemgetter('name')) |
- extensions['optional'].sort(key=itemgetter('name')) |
- |
- self._ApplyAppsTransformations(apps) |
- self._ApplyExtensionsTransformations(extensions) |
- |
- return {'apps': apps, 'extensions': extensions} |
+ def for_templates(manifest_features, platform): |
+ return _AddLevelAnnotations( |
+ _ListifyAndSortDocs( |
+ _RestructureChildren( |
+ features.Filtered(manifest_features, platform)), |
+ app_name=platform.capitalize())) |
+ |
+ manifest_json = Parse(self._file_system.ReadSingle(self._manifest_path)) |
+ manifest_features = features.MergedWith( |
+ features.Parse(Parse(content)), manifest_json) |
+ |
+ return { |
+ 'apps': for_templates(manifest_features, 'app'), |
+ 'extensions': for_templates(manifest_features, 'extension') |
+ } |
def get(self, key): |
- return self._cache.GetFromFile(self._manifest_path)[key] |
+ return self._cache.GetFromFile(self._features_path)[key] |