| 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]
|
|
|