| OLD | NEW |
| (Empty) |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 from collections import defaultdict, Mapping | |
| 6 import traceback | |
| 7 | |
| 8 from third_party.json_schema_compiler import json_parse, idl_schema, idl_parser | |
| 9 | |
| 10 | |
| 11 def RemoveNoDocs(item): | |
| 12 '''Removes nodes that should not be rendered from an API schema. | |
| 13 ''' | |
| 14 if json_parse.IsDict(item): | |
| 15 if item.get('nodoc', False): | |
| 16 return True | |
| 17 for key, value in item.items(): | |
| 18 if RemoveNoDocs(value): | |
| 19 del item[key] | |
| 20 elif type(item) == list: | |
| 21 to_remove = [] | |
| 22 for i in item: | |
| 23 if RemoveNoDocs(i): | |
| 24 to_remove.append(i) | |
| 25 for i in to_remove: | |
| 26 item.remove(i) | |
| 27 return False | |
| 28 | |
| 29 | |
| 30 def DetectInlineableTypes(schema): | |
| 31 '''Look for documents that are only referenced once and mark them as inline. | |
| 32 Actual inlining is done by _InlineDocs. | |
| 33 ''' | |
| 34 if not schema.get('types'): | |
| 35 return | |
| 36 | |
| 37 ignore = frozenset(('value', 'choices')) | |
| 38 refcounts = defaultdict(int) | |
| 39 # Use an explicit stack instead of recursion. | |
| 40 stack = [schema] | |
| 41 | |
| 42 while stack: | |
| 43 node = stack.pop() | |
| 44 if isinstance(node, list): | |
| 45 stack.extend(node) | |
| 46 elif isinstance(node, Mapping): | |
| 47 if '$ref' in node: | |
| 48 refcounts[node['$ref']] += 1 | |
| 49 stack.extend(v for k, v in node.iteritems() if k not in ignore) | |
| 50 | |
| 51 for type_ in schema['types']: | |
| 52 if not 'noinline_doc' in type_: | |
| 53 if refcounts[type_['id']] == 1: | |
| 54 type_['inline_doc'] = True | |
| 55 | |
| 56 | |
| 57 def InlineDocs(schema, retain_inlined_types): | |
| 58 '''Replace '$ref's that refer to inline_docs with the json for those docs. | |
| 59 If |retain_inlined_types| is False, then the inlined nodes are removed | |
| 60 from the schema. | |
| 61 ''' | |
| 62 types = schema.get('types') | |
| 63 if types is None: | |
| 64 return | |
| 65 | |
| 66 inline_docs = {} | |
| 67 types_without_inline_doc = [] | |
| 68 | |
| 69 # Gather the types with inline_doc. | |
| 70 for type_ in types: | |
| 71 if type_.get('inline_doc'): | |
| 72 inline_docs[type_['id']] = type_ | |
| 73 if not retain_inlined_types: | |
| 74 for k in ('description', 'id', 'inline_doc'): | |
| 75 type_.pop(k, None) | |
| 76 else: | |
| 77 types_without_inline_doc.append(type_) | |
| 78 if not retain_inlined_types: | |
| 79 schema['types'] = types_without_inline_doc | |
| 80 | |
| 81 def apply_inline(node): | |
| 82 if isinstance(node, list): | |
| 83 for i in node: | |
| 84 apply_inline(i) | |
| 85 elif isinstance(node, Mapping): | |
| 86 ref = node.get('$ref') | |
| 87 if ref and ref in inline_docs: | |
| 88 node.update(inline_docs[ref]) | |
| 89 del node['$ref'] | |
| 90 for k, v in node.iteritems(): | |
| 91 apply_inline(v) | |
| 92 | |
| 93 apply_inline(schema) | |
| 94 | |
| 95 | |
| 96 def ProcessSchema(path, file_data, retain_inlined_types=False): | |
| 97 '''Parses |file_data| using a method determined by checking the | |
| 98 extension of the file at the given |path|. Then, trims 'nodoc' and if | |
| 99 |retain_inlined_types| is given and False, removes inlineable types from | |
| 100 the parsed schema data. | |
| 101 ''' | |
| 102 def trim_and_inline(schema, is_idl=False): | |
| 103 '''Modifies an API schema in place by removing nodes that shouldn't be | |
| 104 documented and inlining schema types that are only referenced once. | |
| 105 ''' | |
| 106 if RemoveNoDocs(schema): | |
| 107 # A return of True signifies that the entire schema should not be | |
| 108 # documented. Otherwise, only nodes that request 'nodoc' are removed. | |
| 109 return None | |
| 110 if is_idl: | |
| 111 DetectInlineableTypes(schema) | |
| 112 InlineDocs(schema, retain_inlined_types) | |
| 113 return schema | |
| 114 | |
| 115 if path.endswith('.idl'): | |
| 116 idl = idl_schema.IDLSchema(idl_parser.IDLParser().ParseData(file_data)) | |
| 117 # Wrap the result in a list so that it behaves like JSON API data. | |
| 118 return [trim_and_inline(idl.process()[0], is_idl=True)] | |
| 119 | |
| 120 try: | |
| 121 schemas = json_parse.Parse(file_data) | |
| 122 except: | |
| 123 raise ValueError('Cannot parse "%s" as JSON:\n%s' % | |
| 124 (path, traceback.format_exc())) | |
| 125 for schema in schemas: | |
| 126 # Schemas could consist of one API schema (data for a specific API file) | |
| 127 # or multiple (data from extension_api.json). | |
| 128 trim_and_inline(schema) | |
| 129 return schemas | |
| OLD | NEW |