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

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

Issue 12996003: Dynamically generate a heading for Extension Docs API pages (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Revisions, Offline/Online Access (bypassed-hooks) Created 7 years, 7 months 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
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 import collections
5 import copy 6 import copy
7 import json as json_library
6 import logging 8 import logging
7 import os 9 import os
8 import collections
9 10
11 import svn_constants
10 import third_party.json_schema_compiler.json_parse as json_parse 12 import third_party.json_schema_compiler.json_parse as json_parse
11 import third_party.json_schema_compiler.model as model 13 import third_party.json_schema_compiler.model as model
12 import third_party.json_schema_compiler.idl_schema as idl_schema 14 import third_party.json_schema_compiler.idl_schema as idl_schema
13 import third_party.json_schema_compiler.idl_parser as idl_parser 15 import third_party.json_schema_compiler.idl_parser as idl_parser
14 16
15 def _RemoveNoDocs(item): 17 def _RemoveNoDocs(item):
16 if json_parse.IsDict(item): 18 if json_parse.IsDict(item):
17 if item.get('nodoc', False): 19 if item.get('nodoc', False):
18 return True 20 return True
19 for key, value in item.items(): 21 for key, value in item.items():
20 if _RemoveNoDocs(value): 22 if _RemoveNoDocs(value):
21 del item[key] 23 del item[key]
22 elif type(item) == list: 24 elif type(item) == list:
23 to_remove = [] 25 to_remove = []
24 for i in item: 26 for i in item:
25 if _RemoveNoDocs(i): 27 if _RemoveNoDocs(i):
26 to_remove.append(i) 28 to_remove.append(i)
27 for i in to_remove: 29 for i in to_remove:
28 item.remove(i) 30 item.remove(i)
29 return False 31 return False
30 32
31
32 def _InlineDocs(schema): 33 def _InlineDocs(schema):
33 """Replace '$ref's that refer to inline_docs with the json for those docs. 34 """Replace '$ref's that refer to inline_docs with the json for those docs.
34 """ 35 """
35 types = schema.get('types') 36 types = schema.get('types')
36 if types is None: 37 if types is None:
37 return 38 return
38 39
39 inline_docs = {} 40 inline_docs = {}
40 types_without_inline_doc = [] 41 types_without_inline_doc = []
41 42
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 def _FormatValue(value): 74 def _FormatValue(value):
74 """Inserts commas every three digits for integer values. It is magic. 75 """Inserts commas every three digits for integer values. It is magic.
75 """ 76 """
76 s = str(value) 77 s = str(value)
77 return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1]) 78 return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1])
78 79
79 class _JSCModel(object): 80 class _JSCModel(object):
80 """Uses a Model from the JSON Schema Compiler and generates a dict that 81 """Uses a Model from the JSON Schema Compiler and generates a dict that
81 a Handlebar template can use for a data source. 82 a Handlebar template can use for a data source.
82 """ 83 """
83 def __init__(self, json, ref_resolver, disable_refs): 84 def __init__(self,
85 json,
86 ref_resolver,
87 disable_refs,
88 availability_data_source,
89 create_file_system):
84 self._ref_resolver = ref_resolver 90 self._ref_resolver = ref_resolver
85 self._disable_refs = disable_refs 91 self._disable_refs = disable_refs
92 self._availability_data_source = availability_data_source
93 trunk_file_system = create_file_system('trunk')
94 self._intro_tables = json_parse.Parse(trunk_file_system.ReadSingle(
95 '%s/intro_tables.json' % svn_constants.JSON_PATH))
not at google - send to devlin 2013/05/13 21:26:41 I don't think *this* should be trunk though should
epeterson 2013/05/15 07:38:34 Done.
86 clean_json = copy.deepcopy(json) 96 clean_json = copy.deepcopy(json)
87 if _RemoveNoDocs(clean_json): 97 if _RemoveNoDocs(clean_json):
88 self._namespace = None 98 self._namespace = None
89 else: 99 else:
90 _InlineDocs(clean_json) 100 _InlineDocs(clean_json)
91 self._namespace = model.Namespace(clean_json, clean_json['namespace']) 101 self._namespace = model.Namespace(clean_json, clean_json['namespace'])
92 102
93 def _FormatDescription(self, description): 103 def _FormatDescription(self, description):
94 if self._disable_refs: 104 if self._disable_refs:
95 return description 105 return description
96 return self._ref_resolver.ResolveAllLinks(description, 106 return self._ref_resolver.ResolveAllLinks(description,
97 namespace=self._namespace.name) 107 namespace=self._namespace.name)
98 108
99 def _GetLink(self, link): 109 def _GetLink(self, link):
100 if self._disable_refs: 110 if self._disable_refs:
101 type_name = link.split('.', 1)[-1] 111 type_name = link.split('.', 1)[-1]
102 return { 'href': '#type-%s' % type_name, 'text': link, 'name': link } 112 return { 'href': '#type-%s' % type_name, 'text': link, 'name': link }
103 return self._ref_resolver.SafeGetLink(link, namespace=self._namespace.name) 113 return self._ref_resolver.SafeGetLink(link, namespace=self._namespace.name)
104 114
105 def ToDict(self): 115 def ToDict(self):
106 if self._namespace is None: 116 if self._namespace is None:
107 return {} 117 return {}
108 return { 118 return {
109 'name': self._namespace.name, 119 'name': self._namespace.name,
120 'description': self._namespace.description,
121 'availability': self._GetAvailability(),
122 'experimental': self._CheckExperimental(),
123 'permissions_': self._GetPermissions(),
epeterson 2013/05/13 02:38:10 'permissions' is already reserved. There's a note
not at google - send to devlin 2013/05/13 21:26:41 Ohh. Why is it reserved?? Bummer, ok, well permiss
epeterson 2013/05/15 07:38:34 Done.
124 'learn_more': self._GetMoreLearning(),
110 'types': self._GenerateTypes(self._namespace.types.values()), 125 'types': self._GenerateTypes(self._namespace.types.values()),
111 'functions': self._GenerateFunctions(self._namespace.functions), 126 'functions': self._GenerateFunctions(self._namespace.functions),
112 'events': self._GenerateEvents(self._namespace.events), 127 'events': self._GenerateEvents(self._namespace.events),
113 'properties': self._GenerateProperties(self._namespace.properties) 128 'properties': self._GenerateProperties(self._namespace.properties)
114 } 129 }
115 130
131 def _GetAvailability(self):
132 """Finds the earliest stable version of chrome where an API was available
133 using AvailabilityDataSource. If an API hasn't been released to stable yet,
134 then the development channel that the API is currently available on will
135 be returned instead.
136 """
137 if not self._CheckExperimental():
138 return self._availability_data_source.GetAvailability(
139 self._namespace.name)
140 # A special message for experimental APIs' availability will be displayed.
141 return None
142
143 def _CheckExperimental(self):
144 return self._namespace.name.startswith('experimental')
145
146 def _GetPermissions(self):
147 """This is a temporary fix for generating API intro tables automatically.
148 Information on an API's permissions is pulled from a json file so that it
149 can be sent to the templates along with other relevant intro data.
150 """
151 table_info = self._intro_tables.get(self._namespace.name)
152 return table_info.get('Permissions') if table_info else None
153
154 def _GetMoreLearning(self):
not at google - send to devlin 2013/05/13 21:26:41 that is an amusing name :) I don't think that plur
155 """We can't automatically generate the "Learn more" field in an API's.
156 intro table; instead, we pull it from a json file so that it can be sent to
157 the templates along with other relevant intro data.
158 """
159 table_info = self._intro_tables.get(self._namespace.name)
160 return table_info.get('LearnMore') if table_info else None
161
116 def _GenerateTypes(self, types): 162 def _GenerateTypes(self, types):
117 return [self._GenerateType(t) for t in types] 163 return [self._GenerateType(t) for t in types]
118 164
119 def _GenerateType(self, type_): 165 def _GenerateType(self, type_):
120 type_dict = { 166 type_dict = {
121 'name': type_.simple_name, 167 'name': type_.simple_name,
122 'description': self._FormatDescription(type_.description), 168 'description': self._FormatDescription(type_.description),
123 'properties': self._GenerateProperties(type_.properties), 169 'properties': self._GenerateProperties(type_.properties),
124 'functions': self._GenerateFunctions(type_.functions), 170 'functions': self._GenerateFunctions(type_.functions),
125 'events': self._GenerateEvents(type_.events), 171 'events': self._GenerateEvents(type_.events),
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 self._samples = samples 338 self._samples = samples
293 339
294 def get(self, key): 340 def get(self, key):
295 return self._samples.FilterSamples(key, self._api_name) 341 return self._samples.FilterSamples(key, self._api_name)
296 342
297 class APIDataSource(object): 343 class APIDataSource(object):
298 """This class fetches and loads JSON APIs from the FileSystem passed in with 344 """This class fetches and loads JSON APIs from the FileSystem passed in with
299 |compiled_fs_factory|, so the APIs can be plugged into templates. 345 |compiled_fs_factory|, so the APIs can be plugged into templates.
300 """ 346 """
301 class Factory(object): 347 class Factory(object):
302 def __init__(self, compiled_fs_factory, base_path): 348 def __init__(self,
349 compiled_fs_factory,
350 base_path,
351 availability_data_source_factory,
352 create_file_system):
303 def create_compiled_fs(fn, category): 353 def create_compiled_fs(fn, category):
304 return compiled_fs_factory.Create(fn, APIDataSource, category=category) 354 return compiled_fs_factory.Create(fn, APIDataSource, category=category)
305 355
306 self._permissions_cache = create_compiled_fs(self._LoadPermissions, 356 self._permissions_cache = create_compiled_fs(self._LoadPermissions,
307 'permissions') 357 'permissions')
308 358
309 self._json_cache = create_compiled_fs( 359 self._json_cache = create_compiled_fs(
310 lambda api_name, api: self._LoadJsonAPI(api, False), 360 lambda api_name, api: self._LoadJsonAPI(api, False),
311 'json') 361 'json')
312 self._idl_cache = create_compiled_fs( 362 self._idl_cache = create_compiled_fs(
313 lambda api_name, api: self._LoadIdlAPI(api, False), 363 lambda api_name, api: self._LoadIdlAPI(api, False),
314 'idl') 364 'idl')
315 365
316 # These caches are used if an APIDataSource does not want to resolve the 366 # These caches are used if an APIDataSource does not want to resolve the
317 # $refs in an API. This is needed to prevent infinite recursion in 367 # $refs in an API. This is needed to prevent infinite recursion in
318 # ReferenceResolver. 368 # ReferenceResolver.
319 self._json_cache_no_refs = create_compiled_fs( 369 self._json_cache_no_refs = create_compiled_fs(
320 lambda api_name, api: self._LoadJsonAPI(api, True), 370 lambda api_name, api: self._LoadJsonAPI(api, True),
321 'json-no-refs') 371 'json-no-refs')
322 self._idl_cache_no_refs = create_compiled_fs( 372 self._idl_cache_no_refs = create_compiled_fs(
323 lambda api_name, api: self._LoadIdlAPI(api, True), 373 lambda api_name, api: self._LoadIdlAPI(api, True),
324 'idl-no-refs') 374 'idl-no-refs')
325 375
326 self._idl_names_cache = create_compiled_fs(self._GetIDLNames, 'idl-names') 376 self._idl_names_cache = create_compiled_fs(self._GetIDLNames, 'idl-names')
327 self._names_cache = create_compiled_fs(self._GetAllNames, 'names') 377 self._names_cache = create_compiled_fs(self._GetAllNames, 'names')
328 378
329 self._base_path = base_path 379 self._base_path = base_path
330 380 self._availability_data_source = availability_data_source_factory.Create()
381 self._create_file_system = create_file_system
331 # These must be set later via the SetFooDataSourceFactory methods. 382 # These must be set later via the SetFooDataSourceFactory methods.
332 self._ref_resolver_factory = None 383 self._ref_resolver_factory = None
333 self._samples_data_source_factory = None 384 self._samples_data_source_factory = None
334 385
335 def SetSamplesDataSourceFactory(self, samples_data_source_factory): 386 def SetSamplesDataSourceFactory(self, samples_data_source_factory):
336 self._samples_data_source_factory = samples_data_source_factory 387 self._samples_data_source_factory = samples_data_source_factory
337 388
338 def SetReferenceResolverFactory(self, ref_resolver_factory): 389 def SetReferenceResolverFactory(self, ref_resolver_factory):
339 self._ref_resolver_factory = ref_resolver_factory 390 self._ref_resolver_factory = ref_resolver_factory
340 391
(...skipping 25 matching lines...) Expand all
366 samples, 417 samples,
367 disable_refs) 418 disable_refs)
368 419
369 def _LoadPermissions(self, file_name, json_str): 420 def _LoadPermissions(self, file_name, json_str):
370 return json_parse.Parse(json_str) 421 return json_parse.Parse(json_str)
371 422
372 def _LoadJsonAPI(self, api, disable_refs): 423 def _LoadJsonAPI(self, api, disable_refs):
373 return _JSCModel( 424 return _JSCModel(
374 json_parse.Parse(api)[0], 425 json_parse.Parse(api)[0],
375 self._ref_resolver_factory.Create() if not disable_refs else None, 426 self._ref_resolver_factory.Create() if not disable_refs else None,
376 disable_refs).ToDict() 427 disable_refs,
428 self._availability_data_source,
429 self._create_file_system).ToDict()
377 430
378 def _LoadIdlAPI(self, api, disable_refs): 431 def _LoadIdlAPI(self, api, disable_refs):
379 idl = idl_parser.IDLParser().ParseData(api) 432 idl = idl_parser.IDLParser().ParseData(api)
380 return _JSCModel( 433 return _JSCModel(
381 idl_schema.IDLSchema(idl).process()[0], 434 idl_schema.IDLSchema(idl).process()[0],
382 self._ref_resolver_factory.Create() if not disable_refs else None, 435 self._ref_resolver_factory.Create() if not disable_refs else None,
383 disable_refs).ToDict() 436 disable_refs,
437 self._availability_data_source,
438 self._create_file_system).ToDict()
384 439
385 def _GetIDLNames(self, base_dir, apis): 440 def _GetIDLNames(self, base_dir, apis):
386 return self._GetExtNames(apis, ['idl']) 441 return self._GetExtNames(apis, ['idl'])
387 442
388 def _GetAllNames(self, base_dir, apis): 443 def _GetAllNames(self, base_dir, apis):
389 return self._GetExtNames(apis, ['json', 'idl']) 444 return self._GetExtNames(apis, ['json', 'idl'])
390 445
391 def _GetExtNames(self, apis, exts): 446 def _GetExtNames(self, apis, exts):
392 return [model.UnixName(os.path.splitext(api)[0]) for api in apis 447 return [model.UnixName(os.path.splitext(api)[0]) for api in apis
393 if os.path.splitext(api)[1][1:] in exts] 448 if os.path.splitext(api)[1][1:] in exts]
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
450 return feature_data 505 return feature_data
451 506
452 def _GenerateHandlebarContext(self, handlebar_dict, path): 507 def _GenerateHandlebarContext(self, handlebar_dict, path):
453 handlebar_dict['permissions'] = self._GetFeatureData(path) 508 handlebar_dict['permissions'] = self._GetFeatureData(path)
454 handlebar_dict['samples'] = _LazySamplesGetter(path, self._samples) 509 handlebar_dict['samples'] = _LazySamplesGetter(path, self._samples)
455 return handlebar_dict 510 return handlebar_dict
456 511
457 def _GetAsSubdirectory(self, name): 512 def _GetAsSubdirectory(self, name):
458 if name.startswith('experimental_'): 513 if name.startswith('experimental_'):
459 parts = name[len('experimental_'):].split('_', 1) 514 parts = name[len('experimental_'):].split('_', 1)
460 parts[1] = 'experimental_%s' % parts[1] 515 if len(parts) > 1:
461 return '/'.join(parts) 516 parts[1] = 'experimental_%s' % parts[1]
517 return '/'.join(parts)
518 else:
519 return '%s/%s' % (parts[0], name)
462 return name.replace('_', '/', 1) 520 return name.replace('_', '/', 1)
463 521
464 def get(self, key): 522 def _DetermineNamesForGet(self, key):
465 if key.endswith('.html') or key.endswith('.json') or key.endswith('.idl'): 523 if key.endswith('.html') or key.endswith('.json') or key.endswith('.idl'):
466 path, ext = os.path.splitext(key) 524 path, ext = os.path.splitext(key)
467 else: 525 else:
468 path = key 526 path = key
469 unix_name = model.UnixName(path) 527 unix_name = model.UnixName(path)
470 idl_names = self._idl_names_cache.GetFromFileListing(self._base_path)
471 names = self._names_cache.GetFromFileListing(self._base_path) 528 names = self._names_cache.GetFromFileListing(self._base_path)
472 if unix_name not in names and self._GetAsSubdirectory(unix_name) in names: 529 if unix_name not in names and self._GetAsSubdirectory(unix_name) in names:
473 unix_name = self._GetAsSubdirectory(unix_name) 530 unix_name = self._GetAsSubdirectory(unix_name)
531 return (path, unix_name)
474 532
533 def _DetermineCacheForGet(self, unix_name):
534 idl_names = self._idl_names_cache.GetFromFileListing(self._base_path)
475 if self._disable_refs: 535 if self._disable_refs:
476 cache, ext = ( 536 cache, ext = (
477 (self._idl_cache_no_refs, '.idl') if (unix_name in idl_names) else 537 (self._idl_cache_no_refs, '.idl') if (unix_name in idl_names) else
478 (self._json_cache_no_refs, '.json')) 538 (self._json_cache_no_refs, '.json'))
479 else: 539 else:
480 cache, ext = ((self._idl_cache, '.idl') if (unix_name in idl_names) else 540 cache, ext = ((self._idl_cache, '.idl') if (unix_name in idl_names) else
481 (self._json_cache, '.json')) 541 (self._json_cache, '.json'))
542 return (cache, ext)
543
544 def get(self, key):
545 path, unix_name = self._DetermineNamesForGet(key)
546 cache, ext = self._DetermineCacheForGet(unix_name)
482 return self._GenerateHandlebarContext( 547 return self._GenerateHandlebarContext(
483 cache.GetFromFile('%s/%s%s' % (self._base_path, unix_name, ext)), 548 cache.GetFromFile('%s/%s%s' % (self._base_path, unix_name, ext)),
484 path) 549 path)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698