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

Unified Diff: tools/json_schema_compiler/js_externs_generator.py

Issue 511943003: Generate externs automatically from json/idl files: minor changes. Base URL: https://chromium.googlesource.com/chromium/src.git@true_master
Patch Set: Created 6 years, 4 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 side-by-side diff with in-line comments
Download patch
Index: tools/json_schema_compiler/js_externs_generator.py
diff --git a/tools/json_schema_compiler/js_externs_generator.py b/tools/json_schema_compiler/js_externs_generator.py
new file mode 100644
index 0000000000000000000000000000000000000000..f9a77bdb8d46cd689992d6cf3cd4180ada3fc05f
--- /dev/null
+++ b/tools/json_schema_compiler/js_externs_generator.py
@@ -0,0 +1,234 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
hirono 2014/10/03 10:10:42 nit: 2014?
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""
+Generator that produces an externs file for the Closure Compiler.
+
+See https://developers.google.com/closure/compiler/docs/api-tutorial3#externs
+"""
+
+from code import Code
+from model import *
+from schema_util import *
+
+import os
+from datetime import datetime
+
+LICENSE = ("""// Copyright %s The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+""" % datetime.now().year)
+
+class JsExternsGenerator(object):
+ def __init__(self):
+ pass
+
+ def Generate(self, namespace):
+ return _Generator(namespace).Generate()
+
+class _Generator(object):
+ def __init__(self, namespace):
+ self._namespace = namespace
+
+ def Generate(self):
+ """Generates a Code object with the .dart for the entire namespace.
+ """
+ c = Code()
+ (c.Append(LICENSE)
+ .Append()
+ .Append('/** @fileoverview Externs generated from namespace: %s */' %
+ self._namespace.name)
+ .Append())
+
+ for type_ in self._namespace.types.values():
+ c.Cblock(self._GenerateType(type_))
+
+ c.Cblock(self._GenerateNamespaceObject())
+
+ for function in self._namespace.functions.values():
+ c.Cblock(self._GenerateFunction(function))
+
+ for event in self._namespace.events.values():
+ c.Cblock(self._GenerateEvent(event))
+
+ return c
+
+ def _GenerateType(self, type_):
+ """Given a Type object, returns the Code for this type's definition.
+
+ """
+ c = Code()
+
+ # Since enums are just treated as strings for now, don't generate their
+ # type.
+ if type_.property_type is PropertyType.ENUM:
+ return c
+
+ c.Concat(self._GenerateTypeJsDoc(type_))
+
+ if self._IsTypeConstructor(type_):
+ c.Append('var ' + type_.simple_name + ' = function();')
hirono 2014/10/03 10:10:42 Is it OK dropping arguments of constructor?
Vitaly Pavlenko 2014/10/03 23:33:44 You're right, that's a mistake. By the way, will y
+ else:
+ c.Append('var ' + type_.simple_name + ';')
+
+ return c
+
+ def _IsTypeConstructor(self, type_):
+ """Returns true if the given type should be a @constructor. If this returns
+ false, the type is a typedef.
+ """
+ return any(prop.type_.property_type is PropertyType.FUNCTION
+ for prop in type_.properties.values())
+
+ def _GenerateTypeJsDoc(self, type_):
+ """Generates the documentation for a type as a Code.
+
+ Returns an empty code object if the object has no documentation.
+ """
+ c = Code()
+ c.Append('/**')
+
+ if type_.description:
+ for line in type_.description.split('\n'):
+ c.Comment(line, comment_prefix=' * ')
+
+ if self._IsTypeConstructor(type_):
+ c.Comment('@constructor', comment_prefix = ' * ')
+ else:
+ c.Concat(self._GenerateTypedef(type_.properties))
+
+ c.Append(' */')
+ return c
+
+ def _GenerateTypedef(self, properties):
+ """Given an OrderedDict of properties, returns a Code containing a @typedef.
+ """
+ if not properties: return Code()
+
+ lines = []
+ lines.append('@typedef {{')
+ for field, property_ in properties.items():
+ js_type = self._TypeToJsType(property_.type_)
+ if property_.optional:
+ js_type = '(%s|undefined)' % js_type
+ lines.append(' %s: %s,' % (field, js_type))
+
+ # remove last trailing comma
+ lines[-1] = lines[-1][:-1]
+ lines.append('}}')
+ # TODO(tbreisacher): Add '@see <link to documentation>'.
+
+ lines = [' * ' + line for line in lines]
+ codeString = '\n'.join(lines)
Tyler Breisacher (Chromium) 2015/02/25 00:22:05 Can probably inline this? codeString = '\n'.join(
+ c = Code()
+ c.Append(codeString)
+ return c
+
+ def _GenerateFunctionJsDoc(self, function):
+ """Generates the documentation for a function as a Code.
+
+ Returns an empty code object if the object has no documentation.
+ """
+ c = Code()
+ c.Append('/**')
+
+ if function.description:
+ for line in function.description.split('\n'):
+ c.Comment(line, comment_prefix=' * ')
+
+ for param in function.params:
+ js_type = self._TypeToJsType(param.type_)
+
+ if param.optional:
+ js_type += '='
+
+ param_doc = '@param {%s} %s %s' % (js_type,
+ param.name,
+ param.description or '')
+ c.Comment(param_doc, comment_prefix=' * ')
+
+ if function.callback:
+ # TODO(tbreisacher): Convert Function to function() for better
+ # typechecking.
+ js_type = 'Function'
+ if function.callback.optional:
+ js_type += '='
+ param_doc = '@param {%s} %s %s' % (js_type,
+ function.callback.name,
+ function.callback.description or '')
+ c.Comment(param_doc, comment_prefix=' * ')
+
+ if function.returns:
+ return_doc = '@return {%s} %s' % (self._TypeToJsType(function.returns),
+ function.returns.description)
+ c.Comment(return_doc, comment_prefix=' * ')
+
+ c.Append(' */')
+ return c
+
+ def _TypeToJsType(self, type_):
+ """Converts a model.Type to a JS type (number, Array, etc.)"""
+ if type_.property_type in (PropertyType.INTEGER, PropertyType.DOUBLE):
+ return 'number'
+ elif type_.property_type is PropertyType.OBJECT:
+ return 'Object'
+ elif type_.property_type is PropertyType.ARRAY:
+ return 'Array'
+ elif type_.property_type is PropertyType.REF:
+ return type_.ref_type
+ elif type_.property_type.is_fundamental:
+ return type_.property_type.name
+ else:
+ return '?' # TODO make this more specific
Tyler Breisacher (Chromium) 2015/02/25 00:22:05 put someone's name on this TODO. I reluctantly vol
+
+ def _GenerateFunction(self, function):
+ """Generates the code representing a function, including its documentation.
+ For example:
+
+ /**
+ * @param {string} title The new title.
+ */
+ chrome.window.setTitle = function(title) {};
+ """
+ c = Code()
+ params = self._GenerateFunctionParams(function)
+ (c.Concat(self._GenerateFunctionJsDoc(function))
+ .Append('chrome.%s.%s = function(%s) {};' % (self._namespace.name,
+ function.name,
+ params))
+ )
+ return c
+
+ def _GenerateEvent(self, event):
+ """Generates the code representing an event.
+ For example:
+
+ /** @type {!ChromeEvent} */
+ chrome.bookmarks.onChildrenReordered;
+ """
+ c = Code()
+ (c.Append('/** @type {!ChromeEvent} */')
+ .Append('chrome.%s.%s;' % (self._namespace.name, event.name)))
+ return c
+
+ def _GenerateNamespaceObject(self):
+ """Generates the code creating namespace object.
+ For example:
+
+ /**
+ * @const
+ */
+ chrome.bookmarks = {};
+ """
+ c = Code()
+ (c.Append("""/**
+ * @const
+ */""")
+ .Append('chrome.%s = {};' % self._namespace.name))
+ return c
+
+ def _GenerateFunctionParams(self, function):
+ params = function.params[:]
+ if function.callback:
+ params.append(function.callback)
+ return ', '.join(param.name for param in params)

Powered by Google App Engine
This is Rietveld 408576698