Index: tools/json_schema_compiler/js_util.py |
diff --git a/tools/json_schema_compiler/js_externs_generator.py b/tools/json_schema_compiler/js_util.py |
similarity index 37% |
copy from tools/json_schema_compiler/js_externs_generator.py |
copy to tools/json_schema_compiler/js_util.py |
index 20796e9be56895efb7ed5591fac1abd179dee332..f304b98b153d42995fe2aa5b5ff7efd4bcbc0eab 100644 |
--- a/tools/json_schema_compiler/js_externs_generator.py |
+++ b/tools/json_schema_compiler/js_util.py |
@@ -1,154 +1,36 @@ |
# Copyright 2015 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. |
-""" |
-Generator that produces an externs file for the Closure Compiler. |
-Note: This is a work in progress, and generated externs may require tweaking. |
- |
-See https://developers.google.com/closure/compiler/docs/api-tutorial3#externs |
-""" |
from code import Code |
-from model import * |
-from schema_util import * |
+from model import PropertyType |
-import os |
-import sys |
from datetime import datetime |
-import re |
-LICENSE = ("""// Copyright %s The Chromium Authors. All rights reserved. |
+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) |
+""" |
INFO = """// This file was generated by: |
// %s. |
-// NOTE: The format of types has changed. 'FooType' is now |
-// 'chrome.%s.FooType'. |
-// Please run the closure compiler before committing changes. |
-// See https://code.google.com/p/chromium/wiki/ClosureCompilation. |
""" |
-class JsExternsGenerator(object): |
- 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 schema for the entire namespace. |
- """ |
- c = Code() |
- (c.Append(LICENSE) |
- .Append() |
- .Append(INFO % (sys.argv[0], self._namespace.name)) |
- .Append() |
- .Append('/** @fileoverview Externs generated from namespace: %s */' % |
- self._namespace.name) |
- .Append()) |
- |
- c.Cblock(self._GenerateNamespaceObject()) |
- |
- for js_type in self._namespace.types.values(): |
- c.Cblock(self._GenerateType(js_type)) |
- |
- 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, js_type): |
- """Given a Type object, returns the Code for this type's definition. |
- """ |
- c = Code() |
- if js_type.property_type is PropertyType.ENUM: |
- c.Concat(self._GenerateEnumJsDoc(js_type)) |
- else: |
- c.Concat(self._GenerateTypeJsDoc(js_type)) |
- |
- return c |
- |
- def _GenerateEnumJsDoc(self, js_type): |
- """ Given an Enum Type object, returns the Code for the enum's definition. |
- """ |
- c = Code() |
- (c.Sblock(line='/**', line_prefix=' * ') |
- .Append('@enum {string}') |
- .Append(self._GenerateSeeLink('type', js_type.simple_name)) |
- .Eblock(' */')) |
- c.Append('chrome.%s.%s = {' % (self._namespace.name, js_type.name)) |
- |
- def get_property_name(e): |
- # Enum properties are normified to be in ALL_CAPS_STYLE. |
- # Assume enum '1ring-rulesThemAll'. |
- # Transform to '1ring-rules_Them_All'. |
- e = re.sub(r'([a-z])([A-Z])', r'\1_\2', e) |
- # Transform to '1ring_rules_Them_All'. |
- e = re.sub(r'\W', '_', e) |
- # Transform to '_1ring_rules_Them_All'. |
- e = re.sub(r'^(\d)', r'_\1', e) |
- # Transform to '_1RING_RULES_THEM_ALL'. |
- return e.upper() |
- c.Append('\n'.join( |
- [" %s: '%s'," % (get_property_name(v.name), v.name) |
- for v in js_type.enum_values])) |
- c.Append('};') |
- return c |
- |
- def _IsTypeConstructor(self, js_type): |
- """Returns true if the given type should be a @constructor. If this returns |
- false, the type is a typedef. |
+class JsUtil(object): |
+ """A helper class for generating JS Code. |
+ """ |
+ def GetLicense(self): |
+ """Returns the license text for JS extern and interface files. |
""" |
- return any(prop.type_.property_type is PropertyType.FUNCTION |
- for prop in js_type.properties.values()) |
+ return (LICENSE % datetime.now().year) |
- def _GenerateTypeJsDoc(self, js_type): |
- """Generates the documentation for a type as a Code. |
- |
- Returns an empty code object if the object has no documentation. |
+ def GetInfo(self, tool): |
+ """Returns text describing how the file was generated. |
""" |
- c = Code() |
- c.Sblock(line='/**', line_prefix=' * ') |
+ return (INFO % tool) |
- if js_type.description: |
- for line in js_type.description.splitlines(): |
- c.Append(line) |
- |
- is_constructor = self._IsTypeConstructor(js_type) |
- if is_constructor: |
- c.Comment('@constructor', comment_prefix = ' * ', wrap_indent=4) |
- else: |
- c.Concat(self._GenerateTypedef(js_type.properties)) |
- |
- c.Append(self._GenerateSeeLink('type', js_type.simple_name)) |
- c.Eblock(' */') |
- |
- var = 'chrome.%s.%s' % (js_type.namespace.name, js_type.simple_name) |
- if is_constructor: var += ' = function() {}' |
- var += ';' |
- c.Append(var) |
- |
- return c |
- |
- def _GenerateTypedef(self, properties): |
- """Given an OrderedDict of properties, returns a Code containing a @typedef. |
- """ |
- if not properties: return Code() |
- |
- c = Code() |
- c.Append('@typedef {') |
- c.Concat(self._GenerateObjectDefinition(properties), new_line=False) |
- c.Append('}', new_line=False) |
- return c |
- |
- def _GenerateObjectDefinition(self, properties): |
+ def GenerateObjectDefinition(self, namespace_name, properties): |
"""Given an OrderedDict of properties, returns a Code containing the |
description of an object. |
""" |
@@ -164,7 +46,7 @@ class _Generator(object): |
if not first: |
c.Append(',', new_line=False) |
first = False |
- js_type = self._TypeToJsType(prop.type_) |
+ js_type = self._TypeToJsType(namespace_name, prop.type_) |
if prop.optional: |
js_type = (Code(). |
Append('('). |
@@ -177,7 +59,7 @@ class _Generator(object): |
return c |
- def _GenerateFunctionJsDoc(self, function): |
+ def GenerateFunctionJsDoc(self, namespace_name, function): |
"""Generates the documentation for a function as a Code. |
Returns an empty code object if the object has no documentation. |
@@ -199,133 +81,82 @@ class _Generator(object): |
wrap_indent=4, new_line=False) |
for param in function.params: |
- append_field(c, 'param', self._TypeToJsType(param.type_), param.name, |
- param.optional, param.description) |
+ append_field(c, 'param', self._TypeToJsType(namespace_name, param.type_), |
+ param.name, param.optional, param.description) |
if function.callback: |
- append_field(c, 'param', self._FunctionToJsFunction(function.callback), |
+ append_field(c, 'param', |
+ self._FunctionToJsFunction(namespace_name, |
+ function.callback), |
function.callback.name, function.callback.optional, |
function.callback.description) |
if function.returns: |
- append_field(c, 'return', self._TypeToJsType(function.returns), |
+ append_field(c, 'return', |
+ self._TypeToJsType(namespace_name, function.returns), |
'', False, function.returns.description) |
if function.deprecated: |
c.Append('@deprecated %s' % function.deprecated) |
- c.Append(self._GenerateSeeLink('method', function.name)) |
+ c.Append(self.GenerateSeeLink(namespace_name, 'method', function.name)) |
c.Eblock(' */') |
return c |
- def _FunctionToJsFunction(self, function): |
+ def _FunctionToJsFunction(self, namespace_name, function): |
"""Converts a model.Function to a JS type (i.e., function([params])...)""" |
c = Code() |
c.Append('function(') |
for i, param in enumerate(function.params): |
- c.Concat(self._TypeToJsType(param.type_), new_line=False) |
+ c.Concat(self._TypeToJsType(namespace_name, param.type_), new_line=False) |
if i is not len(function.params) - 1: |
c.Append(', ', new_line=False, strip_right=False) |
c.Append('):', new_line=False) |
if function.returns: |
- c.Concat(self._TypeToJsType(function.returns), new_line=False) |
+ c.Concat(self._TypeToJsType(namespace_name, function.returns), |
+ new_line=False) |
else: |
c.Append('void', new_line=False) |
return c |
- def _TypeToJsType(self, js_type): |
+ def _TypeToJsType(self, namespace_name, js_type): |
"""Converts a model.Type to a JS type (number, Array, etc.)""" |
if js_type.property_type in (PropertyType.INTEGER, PropertyType.DOUBLE): |
return Code().Append('number') |
if js_type.property_type is PropertyType.OBJECT: |
if js_type.properties: |
- return self._GenerateObjectDefinition(js_type.properties) |
+ return self.GenerateObjectDefinition(namespace_name, |
+ js_type.properties) |
return Code().Append('Object') |
if js_type.property_type is PropertyType.ARRAY: |
return (Code().Append('!Array<'). |
- Concat(self._TypeToJsType(js_type.item_type), new_line=False). |
+ Concat(self._TypeToJsType(namespace_name, js_type.item_type), |
+ new_line=False). |
Append('>', new_line=False)) |
if js_type.property_type is PropertyType.REF: |
- ref_type = '!chrome.%s.%s' % (self._namespace.name, js_type.ref_type) |
+ ref_type = '!chrome.%s.%s' % (namespace_name, js_type.ref_type) |
return Code().Append(ref_type) |
if js_type.property_type is PropertyType.CHOICES: |
c = Code() |
c.Append('(') |
for i, choice in enumerate(js_type.choices): |
- c.Concat(self._TypeToJsType(choice), new_line=False) |
+ c.Concat(self._TypeToJsType(namespace_name, choice), new_line=False) |
if i is not len(js_type.choices) - 1: |
c.Append('|', new_line=False) |
c.Append(')', new_line=False) |
return c |
if js_type.property_type is PropertyType.FUNCTION: |
- return self._FunctionToJsFunction(js_type.function) |
+ return self._FunctionToJsFunction(namespace_name, js_type.function) |
if js_type.property_type is PropertyType.ANY: |
return Code().Append('*') |
if js_type.property_type.is_fundamental: |
return Code().Append(js_type.property_type.name) |
return Code().Append('?') # TODO(tbreisacher): Make this more specific. |
- 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.Sblock(line='/**', line_prefix=' * ') |
- if (event.description): |
- c.Comment(event.description, comment_prefix='') |
- c.Append('@type {!ChromeEvent}') |
- c.Append(self._GenerateSeeLink('event', event.name)) |
- c.Eblock(' */') |
- c.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) |
- |
- def _GenerateSeeLink(self, object_type, object_name): |
+ def GenerateSeeLink(self, namespace_name, object_type, object_name): |
"""Generates a @see link for a given API 'object' (type, method, or event). |
""" |
@@ -335,4 +166,4 @@ class _Generator(object): |
# Luckily, the doc server has excellent url resolution, and knows exactly |
# what we mean. This saves us from needing any complicated logic here. |
return ('@see https://developer.chrome.com/extensions/%s#%s-%s' % |
- (self._namespace.name, object_type, object_name)) |
+ (namespace_name, object_type, object_name)) |