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: tools/json_schema_compiler/js_externs_generator.py

Issue 1006373003: Generate externs automatically from json/idl files (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Edits Created 5 years, 9 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
(Empty)
1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4 """
5 Generator that produces an externs file for the Closure Compiler.
6 Note: This is a work in progress, and generated externs may require tweaking.
7
8 See https://developers.google.com/closure/compiler/docs/api-tutorial3#externs
9 """
10
11 from code import Code
12 from model import *
13 from schema_util import *
14
15 import os
16 from datetime import datetime
17
18 LICENSE = ("""// Copyright %s The Chromium Authors. All rights reserved.
19 // Use of this source code is governed by a BSD-style license that can be
20 // found in the LICENSE file.
21 """ % datetime.now().year)
22
23 class JsExternsGenerator(object):
24 def __init__(self):
25 pass
Dan Beam 2015/03/19 19:15:02 ^ can't you just omit the __init__ in this case?
Devlin 2015/03/19 20:59:57 Done.
26
27 def Generate(self, namespace):
28 return _Generator(namespace).Generate()
29
30 class _Generator(object):
31 def __init__(self, namespace):
32 self._namespace = namespace
33
34 def Generate(self):
35 """Generates a Code object with the .dart for the entire namespace.
Dan Beam 2015/03/19 19:15:02 the .dart?
Devlin 2015/03/19 20:59:57 Done.
36 """
37 c = Code()
38 (c.Append(LICENSE)
39 .Append()
40 .Append('/** @fileoverview Externs generated from namespace: %s */' %
41 self._namespace.name)
42 .Append())
Dan Beam 2015/03/19 19:15:03 why are these () needed?
Devlin 2015/03/19 20:59:57 Because python doesn't use traditional line breaks
Dan Beam 2015/03/23 21:58:42 it seems like this is already an expression so it
Devlin 2015/03/23 23:20:26 TL;DR: Python line wrapping sucks. This is needed
43
44 for type_ in self._namespace.types.values():
Dan Beam 2015/03/19 19:15:02 maybe type_ -> js_type if we really can't use |typ
Devlin 2015/03/19 20:59:57 Done.
45 c.Cblock(self._GenerateType(type_))
46
47 c.Cblock(self._GenerateNamespaceObject())
48
49 for function in self._namespace.functions.values():
50 c.Cblock(self._GenerateFunction(function))
51
52 for event in self._namespace.events.values():
53 c.Cblock(self._GenerateEvent(event))
54
55 return c
56
57 def _GenerateType(self, type_):
58 """Given a Type object, returns the Code for this type's definition.
59
60 """
61 c = Code()
62
63 # Since enums are just treated as strings for now, don't generate their
64 # type.
65 if type_.property_type is PropertyType.ENUM:
66 return c
67
68 c.Concat(self._GenerateTypeJsDoc(type_))
69
70 if self._IsTypeConstructor(type_):
71 c.Append('var ' + type_.simple_name + ' = function();')
72 else:
73 c.Append('var ' + type_.simple_name + ';')
Dan Beam 2015/03/19 19:15:02 nit: var = 'var ' + type_.simple_name if self
Devlin 2015/03/19 20:59:57 Or even: c.Append('var %s%s;' % (
Dan Beam 2015/03/23 21:58:42 eh, up to you but Tyler's is probably the easiest
Devlin 2015/03/23 23:20:26 Well, I think yours will actually be 4, since I do
74
75 return c
76
77 def _IsTypeConstructor(self, type_):
78 """Returns true if the given type should be a @constructor. If this returns
79 false, the type is a typedef.
80 """
81 return any(prop.type_.property_type is PropertyType.FUNCTION
82 for prop in type_.properties.values())
83
84 def _GenerateTypeJsDoc(self, type_):
85 """Generates the documentation for a type as a Code.
86
87 Returns an empty code object if the object has no documentation.
88 """
89 c = Code()
90 c.Append('/**')
91
92 if type_.description:
93 for line in type_.description.split('\n'):
Dan Beam 2015/03/19 19:15:03 nit: split('\n') -> splitlines()
Devlin 2015/03/19 20:59:57 Done.
94 c.Comment(line, comment_prefix=' * ')
95
96 if self._IsTypeConstructor(type_):
97 c.Comment('@constructor', comment_prefix = ' * ')
98 else:
99 c.Concat(self._GenerateTypedef(type_.properties))
100
101 c.Append(' */')
102 return c
103
104 def _GenerateTypedef(self, properties):
105 """Given an OrderedDict of properties, returns a Code containing a @typedef.
106 """
107 if not properties: return Code()
108
109 lines = []
110 lines.append('@typedef {{')
111 for field, property_ in properties.items():
112 js_type = self._TypeToJsType(property_.type_)
113 if property_.optional:
114 js_type = '(%s|undefined)' % js_type
115 lines.append(' %s: %s,' % (field, js_type))
116
117 # remove last trailing comma
118 lines[-1] = lines[-1][:-1]
119 lines.append('}}')
120 # TODO(tbreisacher): Add '@see <link to documentation>'.
121
122 lines = [' * ' + line for line in lines]
123 code_string = '\n'.join([' * ' + line for line in lines])
124 c = Code()
125 c.Append(code_string)
126 return c
127
128 def _GenerateFunctionJsDoc(self, function):
129 """Generates the documentation for a function as a Code.
130
131 Returns an empty code object if the object has no documentation.
132 """
133 c = Code()
134 c.Append('/**')
135
136 if function.description:
137 for line in function.description.split('\n'):
138 c.Comment(line, comment_prefix=' * ')
139
140 for param in function.params:
141 js_type = self._TypeToJsType(param.type_)
142
143 if param.optional:
144 js_type += '='
145
146 param_doc = '@param {%s} %s %s' % (js_type,
147 param.name,
148 param.description or '')
149 c.Comment(param_doc, comment_prefix=' * ')
150
151 if function.callback:
152 # TODO(tbreisacher): Convert Function to function() for better
153 # typechecking.
154 js_type = 'Function'
155 if function.callback.optional:
156 js_type += '='
157 param_doc = '@param {%s} %s %s' % (js_type,
158 function.callback.name,
159 function.callback.description or '')
160 c.Comment(param_doc, comment_prefix=' * ')
161
162 if function.returns:
163 return_doc = '@return {%s} %s' % (self._TypeToJsType(function.returns),
164 function.returns.description)
165 c.Comment(return_doc, comment_prefix=' * ')
166
167 c.Append(' */')
168 return c
169
170 def _TypeToJsType(self, type_):
171 """Converts a model.Type to a JS type (number, Array, etc.)"""
172 if type_.property_type in (PropertyType.INTEGER, PropertyType.DOUBLE):
173 return 'number'
174 elif type_.property_type is PropertyType.OBJECT:
175 return 'Object'
176 elif type_.property_type is PropertyType.ARRAY:
177 return 'Array'
178 elif type_.property_type is PropertyType.REF:
179 return type_.ref_type
180 elif type_.property_type.is_fundamental:
181 return type_.property_type.name
182 else:
183 return '?' # TODO(tbreisacher): Make this more specific.
184
185 def _GenerateFunction(self, function):
186 """Generates the code representing a function, including its documentation.
187 For example:
188
189 /**
190 * @param {string} title The new title.
191 */
192 chrome.window.setTitle = function(title) {};
193 """
194 c = Code()
195 params = self._GenerateFunctionParams(function)
196 (c.Concat(self._GenerateFunctionJsDoc(function))
197 .Append('chrome.%s.%s = function(%s) {};' % (self._namespace.name,
198 function.name,
199 params))
200 )
201 return c
202
203 def _GenerateEvent(self, event):
204 """Generates the code representing an event.
205 For example:
206
207 /** @type {!ChromeEvent} */
208 chrome.bookmarks.onChildrenReordered;
209 """
210 c = Code()
211 (c.Append('/** @type {!ChromeEvent} */')
212 .Append('chrome.%s.%s;' % (self._namespace.name, event.name)))
213 return c
214
215 def _GenerateNamespaceObject(self):
216 """Generates the code creating namespace object.
217 For example:
218
219 /**
220 * @const
221 */
222 chrome.bookmarks = {};
223 """
224 c = Code()
225 (c.Append("""/**
226 * @const
227 */""")
228 .Append('chrome.%s = {};' % self._namespace.name))
229 return c
230
231 def _GenerateFunctionParams(self, function):
232 params = function.params[:]
233 if function.callback:
234 params.append(function.callback)
235 return ', '.join(param.name for param in params)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698