| OLD | NEW |
| 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 copy | 5 import copy |
| 6 import logging | 6 import logging |
| 7 import os | 7 import os |
| 8 import posixpath | 8 import posixpath |
| 9 | 9 |
| 10 from environment import IsPreviewServer | 10 from environment import IsPreviewServer |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 | 61 |
| 62 | 62 |
| 63 class _JSCModel(object): | 63 class _JSCModel(object): |
| 64 '''Uses a Model from the JSON Schema Compiler and generates a dict that | 64 '''Uses a Model from the JSON Schema Compiler and generates a dict that |
| 65 a Handlebar template can use for a data source. | 65 a Handlebar template can use for a data source. |
| 66 ''' | 66 ''' |
| 67 | 67 |
| 68 def __init__(self, | 68 def __init__(self, |
| 69 api_name, | 69 api_name, |
| 70 api_models, | 70 api_models, |
| 71 ref_resolver, | |
| 72 disable_refs, | 71 disable_refs, |
| 73 availability_finder, | 72 availability_finder, |
| 74 json_cache, | 73 json_cache, |
| 75 template_cache, | 74 template_cache, |
| 76 features_bundle, | 75 features_bundle, |
| 77 event_byname_function): | 76 event_byname_function): |
| 78 self._ref_resolver = ref_resolver | |
| 79 self._disable_refs = disable_refs | 77 self._disable_refs = disable_refs |
| 80 self._availability_finder = availability_finder | 78 self._availability_finder = availability_finder |
| 81 self._api_availabilities = json_cache.GetFromFile( | 79 self._api_availabilities = json_cache.GetFromFile( |
| 82 posixpath.join(JSON_TEMPLATES, 'api_availabilities.json')) | 80 posixpath.join(JSON_TEMPLATES, 'api_availabilities.json')) |
| 83 self._intro_tables = json_cache.GetFromFile( | 81 self._intro_tables = json_cache.GetFromFile( |
| 84 posixpath.join(JSON_TEMPLATES, 'intro_tables.json')) | 82 posixpath.join(JSON_TEMPLATES, 'intro_tables.json')) |
| 85 self._api_features = features_bundle.GetAPIFeatures() | 83 self._api_features = features_bundle.GetAPIFeatures() |
| 86 self._template_cache = template_cache | 84 self._template_cache = template_cache |
| 87 self._event_byname_function = event_byname_function | 85 self._event_byname_function = event_byname_function |
| 88 self._namespace = api_models.GetModel(api_name).Get() | 86 self._namespace = api_models.GetModel(api_name).Get() |
| 89 | 87 |
| 90 def _FormatDescription(self, description): | |
| 91 if self._disable_refs: | |
| 92 return description | |
| 93 return self._ref_resolver.ResolveAllLinks(description, | |
| 94 namespace=self._namespace.name) | |
| 95 | |
| 96 def _GetLink(self, link): | 88 def _GetLink(self, link): |
| 97 if self._disable_refs: | 89 ref = link if '.' in link else (self._namespace.name + '.' + link) |
| 98 type_name = link.split('.', 1)[-1] | 90 return { 'ref': ref, 'text': link, 'name': link } |
| 99 return { 'href': '#type-%s' % type_name, 'text': link, 'name': link } | |
| 100 return self._ref_resolver.SafeGetLink(link, namespace=self._namespace.name) | |
| 101 | 91 |
| 102 def ToDict(self): | 92 def ToDict(self): |
| 103 if self._namespace is None: | 93 if self._namespace is None: |
| 104 return {} | 94 return {} |
| 105 chrome_dot_name = 'chrome.%s' % self._namespace.name | 95 chrome_dot_name = 'chrome.%s' % self._namespace.name |
| 106 as_dict = { | 96 as_dict = { |
| 107 'name': self._namespace.name, | 97 'name': self._namespace.name, |
| 108 'namespace': self._namespace.documentation_options.get('namespace', | 98 'namespace': self._namespace.documentation_options.get('namespace', |
| 109 chrome_dot_name), | 99 chrome_dot_name), |
| 110 'title': self._namespace.documentation_options.get('title', | 100 'title': self._namespace.documentation_options.get('title', |
| (...skipping 27 matching lines...) Expand all Loading... |
| 138 | 128 |
| 139 def _IsExperimental(self): | 129 def _IsExperimental(self): |
| 140 return self._namespace.name.startswith('experimental') | 130 return self._namespace.name.startswith('experimental') |
| 141 | 131 |
| 142 def _GenerateTypes(self, types): | 132 def _GenerateTypes(self, types): |
| 143 return [self._GenerateType(t) for t in types] | 133 return [self._GenerateType(t) for t in types] |
| 144 | 134 |
| 145 def _GenerateType(self, type_): | 135 def _GenerateType(self, type_): |
| 146 type_dict = { | 136 type_dict = { |
| 147 'name': type_.simple_name, | 137 'name': type_.simple_name, |
| 148 'description': self._FormatDescription(type_.description), | 138 'description': type_.description, |
| 149 'properties': self._GenerateProperties(type_.properties), | 139 'properties': self._GenerateProperties(type_.properties), |
| 150 'functions': self._GenerateFunctions(type_.functions), | 140 'functions': self._GenerateFunctions(type_.functions), |
| 151 'events': self._GenerateEvents(type_.events), | 141 'events': self._GenerateEvents(type_.events), |
| 152 'id': _CreateId(type_, 'type') | 142 'id': _CreateId(type_, 'type') |
| 153 } | 143 } |
| 154 self._RenderTypeInformation(type_, type_dict) | 144 self._RenderTypeInformation(type_, type_dict) |
| 155 return type_dict | 145 return type_dict |
| 156 | 146 |
| 157 def _GenerateFunctions(self, functions): | 147 def _GenerateFunctions(self, functions): |
| 158 return [self._GenerateFunction(f) for f in functions.values()] | 148 return [self._GenerateFunction(f) for f in functions.values()] |
| 159 | 149 |
| 160 def _GenerateFunction(self, function): | 150 def _GenerateFunction(self, function): |
| 161 function_dict = { | 151 function_dict = { |
| 162 'name': function.simple_name, | 152 'name': function.simple_name, |
| 163 'description': self._FormatDescription(function.description), | 153 'description': function.description, |
| 164 'callback': self._GenerateCallback(function.callback), | 154 'callback': self._GenerateCallback(function.callback), |
| 165 'parameters': [], | 155 'parameters': [], |
| 166 'returns': None, | 156 'returns': None, |
| 167 'id': _CreateId(function, 'method') | 157 'id': _CreateId(function, 'method') |
| 168 } | 158 } |
| 169 self._AddCommonProperties(function_dict, function) | 159 self._AddCommonProperties(function_dict, function) |
| 170 if function.returns: | 160 if function.returns: |
| 171 function_dict['returns'] = self._GenerateType(function.returns) | 161 function_dict['returns'] = self._GenerateType(function.returns) |
| 172 for param in function.params: | 162 for param in function.params: |
| 173 function_dict['parameters'].append(self._GenerateProperty(param)) | 163 function_dict['parameters'].append(self._GenerateProperty(param)) |
| 174 if function.callback is not None: | 164 if function.callback is not None: |
| 175 # Show the callback as an extra parameter. | 165 # Show the callback as an extra parameter. |
| 176 function_dict['parameters'].append( | 166 function_dict['parameters'].append( |
| 177 self._GenerateCallbackProperty(function.callback)) | 167 self._GenerateCallbackProperty(function.callback)) |
| 178 if len(function_dict['parameters']) > 0: | 168 if len(function_dict['parameters']) > 0: |
| 179 function_dict['parameters'][-1]['last'] = True | 169 function_dict['parameters'][-1]['last'] = True |
| 180 return function_dict | 170 return function_dict |
| 181 | 171 |
| 182 def _GenerateEvents(self, events): | 172 def _GenerateEvents(self, events): |
| 183 return [self._GenerateEvent(e) for e in events.values() | 173 return [self._GenerateEvent(e) for e in events.values() |
| 184 if not e.supports_dom] | 174 if not e.supports_dom] |
| 185 | 175 |
| 186 def _GenerateDomEvents(self, events): | 176 def _GenerateDomEvents(self, events): |
| 187 return [self._GenerateEvent(e) for e in events.values() | 177 return [self._GenerateEvent(e) for e in events.values() |
| 188 if e.supports_dom] | 178 if e.supports_dom] |
| 189 | 179 |
| 190 def _GenerateEvent(self, event): | 180 def _GenerateEvent(self, event): |
| 191 event_dict = { | 181 event_dict = { |
| 192 'name': event.simple_name, | 182 'name': event.simple_name, |
| 193 'description': self._FormatDescription(event.description), | 183 'description': event.description, |
| 194 'filters': [self._GenerateProperty(f) for f in event.filters], | 184 'filters': [self._GenerateProperty(f) for f in event.filters], |
| 195 'conditions': [self._GetLink(condition) | 185 'conditions': [self._GetLink(condition) |
| 196 for condition in event.conditions], | 186 for condition in event.conditions], |
| 197 'actions': [self._GetLink(action) for action in event.actions], | 187 'actions': [self._GetLink(action) for action in event.actions], |
| 198 'supportsRules': event.supports_rules, | 188 'supportsRules': event.supports_rules, |
| 199 'supportsListeners': event.supports_listeners, | 189 'supportsListeners': event.supports_listeners, |
| 200 'properties': [], | 190 'properties': [], |
| 201 'id': _CreateId(event, 'event'), | 191 'id': _CreateId(event, 'event'), |
| 202 'byName': {}, | 192 'byName': {}, |
| 203 } | 193 } |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 # Make sure we generate property info for arrays, too. | 250 # Make sure we generate property info for arrays, too. |
| 261 # TODO(kalman): what about choices? | 251 # TODO(kalman): what about choices? |
| 262 if type_.property_type == model.PropertyType.ARRAY: | 252 if type_.property_type == model.PropertyType.ARRAY: |
| 263 properties = type_.item_type.properties | 253 properties = type_.item_type.properties |
| 264 else: | 254 else: |
| 265 properties = type_.properties | 255 properties = type_.properties |
| 266 | 256 |
| 267 property_dict = { | 257 property_dict = { |
| 268 'name': property_.simple_name, | 258 'name': property_.simple_name, |
| 269 'optional': property_.optional, | 259 'optional': property_.optional, |
| 270 'description': self._FormatDescription(property_.description), | 260 'description': property_.description, |
| 271 'properties': self._GenerateProperties(type_.properties), | 261 'properties': self._GenerateProperties(type_.properties), |
| 272 'functions': self._GenerateFunctions(type_.functions), | 262 'functions': self._GenerateFunctions(type_.functions), |
| 273 'parameters': [], | 263 'parameters': [], |
| 274 'returns': None, | 264 'returns': None, |
| 275 'id': _CreateId(property_, 'property') | 265 'id': _CreateId(property_, 'property') |
| 276 } | 266 } |
| 277 self._AddCommonProperties(property_dict, property_) | 267 self._AddCommonProperties(property_dict, property_) |
| 278 | 268 |
| 279 if type_.property_type == model.PropertyType.FUNCTION: | 269 if type_.property_type == model.PropertyType.FUNCTION: |
| 280 function = type_.function | 270 function = type_.function |
| 281 for param in function.params: | 271 for param in function.params: |
| 282 property_dict['parameters'].append(self._GenerateProperty(param)) | 272 property_dict['parameters'].append(self._GenerateProperty(param)) |
| 283 if function.returns: | 273 if function.returns: |
| 284 property_dict['returns'] = self._GenerateType(function.returns) | 274 property_dict['returns'] = self._GenerateType(function.returns) |
| 285 | 275 |
| 286 value = property_.value | 276 value = property_.value |
| 287 if value is not None: | 277 if value is not None: |
| 288 if isinstance(value, int): | 278 if isinstance(value, int): |
| 289 property_dict['value'] = _FormatValue(value) | 279 property_dict['value'] = _FormatValue(value) |
| 290 else: | 280 else: |
| 291 property_dict['value'] = value | 281 property_dict['value'] = value |
| 292 else: | 282 else: |
| 293 self._RenderTypeInformation(type_, property_dict) | 283 self._RenderTypeInformation(type_, property_dict) |
| 294 | 284 |
| 295 return property_dict | 285 return property_dict |
| 296 | 286 |
| 297 def _GenerateCallbackProperty(self, callback): | 287 def _GenerateCallbackProperty(self, callback): |
| 298 property_dict = { | 288 property_dict = { |
| 299 'name': callback.simple_name, | 289 'name': callback.simple_name, |
| 300 'description': self._FormatDescription(callback.description), | 290 'description': callback.description, |
| 301 'optional': callback.optional, | 291 'optional': callback.optional, |
| 302 'is_callback': True, | 292 'is_callback': True, |
| 303 'id': _CreateId(callback, 'property'), | 293 'id': _CreateId(callback, 'property'), |
| 304 'simple_type': 'function', | 294 'simple_type': 'function', |
| 305 } | 295 } |
| 306 if (callback.parent is not None and | 296 if (callback.parent is not None and |
| 307 not isinstance(callback.parent, model.Namespace)): | 297 not isinstance(callback.parent, model.Namespace)): |
| 308 property_dict['parentName'] = callback.parent.simple_name | 298 property_dict['parentName'] = callback.parent.simple_name |
| 309 return property_dict | 299 return property_dict |
| 310 | 300 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 350 intro_rows.append(misc_row) | 340 intro_rows.append(misc_row) |
| 351 | 341 |
| 352 return intro_rows | 342 return intro_rows |
| 353 | 343 |
| 354 def _GetIntroDescriptionRow(self): | 344 def _GetIntroDescriptionRow(self): |
| 355 ''' Generates the 'Description' row data for an API intro table. | 345 ''' Generates the 'Description' row data for an API intro table. |
| 356 ''' | 346 ''' |
| 357 return { | 347 return { |
| 358 'title': 'Description', | 348 'title': 'Description', |
| 359 'content': [ | 349 'content': [ |
| 360 { 'text': self._FormatDescription(self._namespace.description) } | 350 { 'text': self._namespace.description } |
| 361 ] | 351 ] |
| 362 } | 352 } |
| 363 | 353 |
| 364 def _GetIntroAvailabilityRow(self): | 354 def _GetIntroAvailabilityRow(self): |
| 365 ''' Generates the 'Availability' row data for an API intro table. | 355 ''' Generates the 'Availability' row data for an API intro table. |
| 366 ''' | 356 ''' |
| 367 if self._IsExperimental(): | 357 if self._IsExperimental(): |
| 368 status = 'experimental' | 358 status = 'experimental' |
| 369 version = None | 359 version = None |
| 370 else: | 360 else: |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 448 # If there is a 'partial' argument and it hasn't already been | 438 # If there is a 'partial' argument and it hasn't already been |
| 449 # converted to a Handlebar object, transform it to a template. | 439 # converted to a Handlebar object, transform it to a template. |
| 450 if 'partial' in node: | 440 if 'partial' in node: |
| 451 node['partial'] = self._template_cache.GetFromFile( | 441 node['partial'] = self._template_cache.GetFromFile( |
| 452 posixpath.join(PRIVATE_TEMPLATES, node['partial'])).Get() | 442 posixpath.join(PRIVATE_TEMPLATES, node['partial'])).Get() |
| 453 misc_rows.append({ 'title': category, 'content': content }) | 443 misc_rows.append({ 'title': category, 'content': content }) |
| 454 return misc_rows | 444 return misc_rows |
| 455 | 445 |
| 456 def _AddCommonProperties(self, target, src): | 446 def _AddCommonProperties(self, target, src): |
| 457 if src.deprecated is not None: | 447 if src.deprecated is not None: |
| 458 target['deprecated'] = self._FormatDescription( | 448 target['deprecated'] = src.deprecated |
| 459 src.deprecated) | |
| 460 if (src.parent is not None and | 449 if (src.parent is not None and |
| 461 not isinstance(src.parent, model.Namespace)): | 450 not isinstance(src.parent, model.Namespace)): |
| 462 target['parentName'] = src.parent.simple_name | 451 target['parentName'] = src.parent.simple_name |
| 463 | 452 |
| 464 | 453 |
| 465 class _LazySamplesGetter(object): | 454 class _LazySamplesGetter(object): |
| 466 '''This class is needed so that an extensions API page does not have to fetch | 455 '''This class is needed so that an extensions API page does not have to fetch |
| 467 the apps samples page and vice versa. | 456 the apps samples page and vice versa. |
| 468 ''' | 457 ''' |
| 469 | 458 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 492 self._template_cache = compiled_fs_factory.ForTemplates(file_system) | 481 self._template_cache = compiled_fs_factory.ForTemplates(file_system) |
| 493 self._availability_finder = availability_finder | 482 self._availability_finder = availability_finder |
| 494 self._api_models = api_models | 483 self._api_models = api_models |
| 495 self._features_bundle = features_bundle | 484 self._features_bundle = features_bundle |
| 496 self._model_cache_refs = object_store_creator.Create( | 485 self._model_cache_refs = object_store_creator.Create( |
| 497 APIDataSource, 'model-cache-refs') | 486 APIDataSource, 'model-cache-refs') |
| 498 self._model_cache_no_refs = object_store_creator.Create( | 487 self._model_cache_no_refs = object_store_creator.Create( |
| 499 APIDataSource, 'model-cache-no-refs') | 488 APIDataSource, 'model-cache-no-refs') |
| 500 | 489 |
| 501 # These must be set later via the SetFooDataSourceFactory methods. | 490 # These must be set later via the SetFooDataSourceFactory methods. |
| 502 self._ref_resolver_factory = None | |
| 503 self._samples_data_source_factory = None | 491 self._samples_data_source_factory = None |
| 504 | 492 |
| 505 # This caches the result of _LoadEventByName. | 493 # This caches the result of _LoadEventByName. |
| 506 self._event_byname = None | 494 self._event_byname = None |
| 507 | 495 |
| 508 def SetSamplesDataSourceFactory(self, samples_data_source_factory): | 496 def SetSamplesDataSourceFactory(self, samples_data_source_factory): |
| 509 self._samples_data_source_factory = samples_data_source_factory | 497 self._samples_data_source_factory = samples_data_source_factory |
| 510 | 498 |
| 511 def SetReferenceResolverFactory(self, ref_resolver_factory): | |
| 512 self._ref_resolver_factory = ref_resolver_factory | |
| 513 | |
| 514 def Create(self, request): | 499 def Create(self, request): |
| 515 '''Creates an APIDataSource. | 500 '''Creates an APIDataSource. |
| 516 ''' | 501 ''' |
| 517 if self._samples_data_source_factory is None: | 502 if self._samples_data_source_factory is None: |
| 518 # Only error if there is a request, which means this APIDataSource is | 503 # Only error if there is a request, which means this APIDataSource is |
| 519 # actually being used to render a page. | 504 # actually being used to render a page. |
| 520 if request is not None: | 505 if request is not None: |
| 521 logging.error('SamplesDataSource.Factory was never set in ' | 506 logging.error('SamplesDataSource.Factory was never set in ' |
| 522 'APIDataSource.Factory.') | 507 'APIDataSource.Factory.') |
| 523 samples = None | 508 samples = None |
| (...skipping 16 matching lines...) Expand all Loading... |
| 540 return self._model_cache_refs | 525 return self._model_cache_refs |
| 541 | 526 |
| 542 def _GetSchemaModel(self, api_name, disable_refs): | 527 def _GetSchemaModel(self, api_name, disable_refs): |
| 543 jsc_model = self._GetModelCache(disable_refs).Get(api_name).Get() | 528 jsc_model = self._GetModelCache(disable_refs).Get(api_name).Get() |
| 544 if jsc_model is not None: | 529 if jsc_model is not None: |
| 545 return jsc_model | 530 return jsc_model |
| 546 | 531 |
| 547 jsc_model = _JSCModel( | 532 jsc_model = _JSCModel( |
| 548 api_name, | 533 api_name, |
| 549 self._api_models, | 534 self._api_models, |
| 550 self._ref_resolver_factory.Create() if not disable_refs else None, | |
| 551 disable_refs, | 535 disable_refs, |
| 552 self._availability_finder, | 536 self._availability_finder, |
| 553 self._json_cache, | 537 self._json_cache, |
| 554 self._template_cache, | 538 self._template_cache, |
| 555 self._features_bundle, | 539 self._features_bundle, |
| 556 self._LoadEventByName).ToDict() | 540 self._LoadEventByName).ToDict() |
| 557 | 541 |
| 558 self._GetModelCache(disable_refs).Set(api_name, jsc_model) | 542 self._GetModelCache(disable_refs).Set(api_name, jsc_model) |
| 559 return jsc_model | 543 return jsc_model |
| 560 | 544 |
| 561 def __init__(self, get_schema_model, samples): | 545 def __init__(self, get_schema_model, samples): |
| 562 self._get_schema_model = get_schema_model | 546 self._get_schema_model = get_schema_model |
| 563 self._samples = samples | 547 self._samples = samples |
| 564 | 548 |
| 565 def _GenerateHandlebarContext(self, handlebar_dict): | 549 def _GenerateHandlebarContext(self, handlebar_dict): |
| 566 # Parsing samples on the preview server takes seconds and doesn't add | 550 # Parsing samples on the preview server takes seconds and doesn't add |
| 567 # anything. Don't do it. | 551 # anything. Don't do it. |
| 568 if not IsPreviewServer(): | 552 if not IsPreviewServer(): |
| 569 handlebar_dict['samples'] = _LazySamplesGetter( | 553 handlebar_dict['samples'] = _LazySamplesGetter( |
| 570 handlebar_dict['name'], | 554 handlebar_dict['name'], |
| 571 self._samples) | 555 self._samples) |
| 572 return handlebar_dict | 556 return handlebar_dict |
| 573 | 557 |
| 574 def get(self, api_name, disable_refs=False): | 558 def get(self, api_name, disable_refs=False): |
| 575 return self._GenerateHandlebarContext( | 559 return self._GenerateHandlebarContext( |
| 576 self._get_schema_model(api_name, disable_refs)) | 560 self._get_schema_model(api_name, disable_refs)) |
| OLD | NEW |