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

Side by Side Diff: chrome/common/extensions/docs/server2/reference_resolver.py

Issue 55913003: Docserver: Fix 3 issues relating to finding API references in sample files, (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 1 month 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 from file_system import FileNotFoundError 5 from copy import deepcopy
6 import logging 6 import logging
7 import re 7 import re
8 import string 8 import string
9 9
10 from file_system import FileNotFoundError
11
12
10 def _ClassifySchemaNode(node_name, api): 13 def _ClassifySchemaNode(node_name, api):
11 """Attempt to classify |node_name| in an API, determining whether |node_name| 14 """Attempt to classify |node_name| in an API, determining whether |node_name|
12 refers to a type, function, event, or property in |api|. 15 refers to a type, function, event, or property in |api|.
13 """ 16 """
14 if '.' in node_name: 17 if '.' in node_name:
15 node_name, rest = node_name.split('.', 1) 18 node_name, rest = node_name.split('.', 1)
16 else: 19 else:
17 rest = None 20 rest = None
18 for key, group in [('types', 'type'), 21 for key, group in [('types', 'type'),
19 ('functions', 'method'), 22 ('functions', 'method'),
20 ('events', 'event'), 23 ('events', 'event'),
21 ('properties', 'property')]: 24 ('properties', 'property')]:
22 for item in api.get(key, []): 25 for item in api.get(key, []):
23 if item['name'] == node_name: 26 if item['name'] == node_name:
24 if rest is not None: 27 if rest is not None:
25 ret = _ClassifySchemaNode(rest, item) 28 ret = _ClassifySchemaNode(rest, item)
26 if ret is not None: 29 if ret is not None:
27 return ret 30 return ret
28 else: 31 else:
29 return group, node_name 32 return group, node_name
30 return None 33 return None
31 34
32 def _MakeKey(namespace, ref, title): 35
33 return '%s.%s.%s' % (namespace, ref, title) 36 def _MakeKey(namespace, ref):
37 key = '%s/%s' % (namespace, ref)
38 # AppEngine doesn't like keys > 500, but there will be some other stuff
39 # that goes into this key, so truncate it earlier. This shoudn't be
40 # happening anyway unless there's a bug, such as http://crbug.com/314102.
41 max_size = 256
42 if len(key) > max_size:
43 logging.error('Key was >%s characters: %s' % (max_size, key))
44 key = key[:max_size]
45 return key
46
34 47
35 class ReferenceResolver(object): 48 class ReferenceResolver(object):
36 """Resolves references to $ref's by searching through the APIs to find the 49 """Resolves references to $ref's by searching through the APIs to find the
37 correct node. 50 correct node.
38 51
39 $ref's have two forms: 52 $ref's have two forms:
40 53
41 $ref:api.node - Replaces the $ref with a link to node on the API page. The 54 $ref:api.node - Replaces the $ref with a link to node on the API page. The
42 title is set to the name of the node. 55 title is set to the name of the node.
43 56
(...skipping 17 matching lines...) Expand all
61 return ReferenceResolver( 74 return ReferenceResolver(
62 self._api_data_source_factory.Create(None), 75 self._api_data_source_factory.Create(None),
63 self._api_models, 76 self._api_models,
64 self._object_store_creator.Create(ReferenceResolver)) 77 self._object_store_creator.Create(ReferenceResolver))
65 78
66 def __init__(self, api_data_source, api_models, object_store): 79 def __init__(self, api_data_source, api_models, object_store):
67 self._api_data_source = api_data_source 80 self._api_data_source = api_data_source
68 self._api_models = api_models 81 self._api_models = api_models
69 self._object_store = object_store 82 self._object_store = object_store
70 83
71 def _GetRefLink(self, ref, api_list, namespace, title): 84 def _GetRefLink(self, ref, api_list, namespace):
72 # Check nodes within each API the ref might refer to. 85 # Check nodes within each API the ref might refer to.
73 parts = ref.split('.') 86 parts = ref.split('.')
74 for i, part in enumerate(parts): 87 for i, part in enumerate(parts):
75 api_name = '.'.join(parts[:i]) 88 api_name = '.'.join(parts[:i])
76 if api_name not in api_list: 89 if api_name not in api_list:
77 continue 90 continue
78 try: 91 try:
79 api = self._api_data_source.get(api_name, disable_refs=True) 92 api = self._api_data_source.get(api_name, disable_refs=True)
80 except FileNotFoundError: 93 except FileNotFoundError:
81 continue 94 continue
(...skipping 15 matching lines...) Expand all
97 break 110 break
98 if node_info is None: 111 if node_info is None:
99 continue 112 continue
100 else: 113 else:
101 text = ref 114 text = ref
102 category, node_name = node_info 115 category, node_name = node_info
103 if namespace is not None and text.startswith('%s.' % namespace): 116 if namespace is not None and text.startswith('%s.' % namespace):
104 text = text[len('%s.' % namespace):] 117 text = text[len('%s.' % namespace):]
105 return { 118 return {
106 'href': '%s.html#%s-%s' % (api_name, category, name.replace('.', '-')), 119 'href': '%s.html#%s-%s' % (api_name, category, name.replace('.', '-')),
107 'text': title if title else text, 120 'text': text,
108 'name': node_name 121 'name': node_name
109 } 122 }
110 123
111 # If it's not a reference to an API node it might just be a reference to an 124 # If it's not a reference to an API node it might just be a reference to an
112 # API. Check this last so that links within APIs take precedence over links 125 # API. Check this last so that links within APIs take precedence over links
113 # to other APIs. 126 # to other APIs.
114 if ref in api_list: 127 if ref in api_list:
115 return { 128 return {
116 'href': '%s.html' % ref, 129 'href': '%s.html' % ref,
117 'text': title if title else ref, 130 'text': ref,
118 'name': ref 131 'name': ref
119 } 132 }
120 133
121 return None 134 return None
122 135
123 def GetLink(self, ref, namespace=None, title=None): 136 def GetLink(self, ref, namespace=None, title=None):
124 """Resolve $ref |ref| in namespace |namespace| if not None, returning None 137 """Resolve $ref |ref| in namespace |namespace| if not None, returning None
125 if it cannot be resolved. 138 if it cannot be resolved.
126 """ 139 """
127 link = self._object_store.Get(_MakeKey(namespace, ref, title)).Get() 140 db_key = _MakeKey(namespace, ref)
128 if link is not None: 141 link = self._object_store.Get(db_key).Get()
129 return link 142 if link is None:
130 143 api_list = self._api_models.GetNames()
131 api_list = self._api_models.GetNames() 144 link = self._GetRefLink(ref, api_list, namespace)
132 link = self._GetRefLink(ref, api_list, namespace, title) 145 if link is None and namespace is not None:
133 146 # Try to resolve the ref in the current namespace if there is one.
134 if link is None and namespace is not None: 147 link = self._GetRefLink('%s.%s' % (namespace, ref), api_list, namespace)
135 # Try to resolve the ref in the current namespace if there is one. 148 if link is None:
136 link = self._GetRefLink('%s.%s' % (namespace, ref), 149 return None
137 api_list, 150 self._object_store.Set(db_key, link)
138 namespace, 151 else:
139 title) 152 link = deepcopy(link)
140 153 if title is not None:
141 if link is not None: 154 link['text'] = title
142 self._object_store.Set(_MakeKey(namespace, ref, title), link)
143 return link 155 return link
144 156
145 def SafeGetLink(self, ref, namespace=None, title=None): 157 def SafeGetLink(self, ref, namespace=None, title=None):
146 """Resolve $ref |ref| in namespace |namespace|, or globally if None. If it 158 """Resolve $ref |ref| in namespace |namespace|, or globally if None. If it
147 cannot be resolved, pretend like it is a link to a type. 159 cannot be resolved, pretend like it is a link to a type.
148 """ 160 """
149 ref_data = self.GetLink(ref, namespace=namespace, title=title) 161 ref_data = self.GetLink(ref, namespace=namespace, title=title)
150 if ref_data is not None: 162 if ref_data is not None:
151 return ref_data 163 return ref_data
152 logging.error('$ref %s could not be resolved in namespace %s.' % 164 logging.error('$ref %s could not be resolved in namespace %s.' %
153 (ref, namespace)) 165 (ref, namespace))
154 type_name = ref.rsplit('.', 1)[-1] 166 type_name = ref.rsplit('.', 1)[-1]
155 return { 167 return {
156 'href': '#type-%s' % type_name, 168 'href': '#type-%s' % type_name,
157 'text': title if title else ref, 169 'text': title or ref,
158 'name': ref 170 'name': ref
159 } 171 }
160 172
161 def ResolveAllLinks(self, text, namespace=None): 173 def ResolveAllLinks(self, text, namespace=None):
162 """This method will resolve all $ref links in |text| using namespace 174 """This method will resolve all $ref links in |text| using namespace
163 |namespace| if not None. Any links that cannot be resolved will be replaced 175 |namespace| if not None. Any links that cannot be resolved will be replaced
164 using the default link format that |SafeGetLink| uses. 176 using the default link format that |SafeGetLink| uses.
165 """ 177 """
166 if text is None or '$ref:' not in text: 178 if text is None or '$ref:' not in text:
167 return text 179 return text
(...skipping 20 matching lines...) Expand all
188 ref = '' 200 ref = ''
189 rest = ref_and_rest 201 rest = ref_and_rest
190 else: 202 else:
191 ref = match.group() 203 ref = match.group()
192 rest = ref_and_rest[match.end():] 204 rest = ref_and_rest[match.end():]
193 205
194 ref_dict = self.SafeGetLink(ref, namespace=namespace, title=title) 206 ref_dict = self.SafeGetLink(ref, namespace=namespace, title=title)
195 formatted_text.append('<a href="%(href)s">%(text)s</a>%(rest)s' % 207 formatted_text.append('<a href="%(href)s">%(text)s</a>%(rest)s' %
196 { 'href': ref_dict['href'], 'text': ref_dict['text'], 'rest': rest }) 208 { 'href': ref_dict['href'], 'text': ref_dict['text'], 'rest': rest })
197 return ''.join(formatted_text) 209 return ''.join(formatted_text)
OLDNEW
« no previous file with comments | « chrome/common/extensions/docs/server2/cron.yaml ('k') | chrome/common/extensions/docs/server2/samples_data_source.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698