| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/env python | |
| 2 # Copyright (c) 2011 Google Inc. All rights reserved. | |
| 3 # | |
| 4 # Redistribution and use in source and binary forms, with or without | |
| 5 # modification, are permitted provided that the following conditions are | |
| 6 # met: | |
| 7 # | |
| 8 # * Redistributions of source code must retain the above copyright | |
| 9 # notice, this list of conditions and the following disclaimer. | |
| 10 # * Redistributions in binary form must reproduce the above | |
| 11 # copyright notice, this list of conditions and the following disclaimer | |
| 12 # in the documentation and/or other materials provided with the | |
| 13 # distribution. | |
| 14 # * Neither the name of Google Inc. nor the names of its | |
| 15 # contributors may be used to endorse or promote products derived from | |
| 16 # this software without specific prior written permission. | |
| 17 # | |
| 18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 29 | |
| 30 import re | |
| 31 | |
| 32 type_traits = { | |
| 33 "any": "*", | |
| 34 "string": "string", | |
| 35 "integer": "number", | |
| 36 "number": "number", | |
| 37 "boolean": "boolean", | |
| 38 "array": "Array.<*>", | |
| 39 "object": "Object", | |
| 40 } | |
| 41 | |
| 42 ref_types = {} | |
| 43 | |
| 44 | |
| 45 def full_qualified_type_id(domain_name, type_id): | |
| 46 if type_id.find(".") == -1: | |
| 47 return "%s.%s" % (domain_name, type_id) | |
| 48 return type_id | |
| 49 | |
| 50 | |
| 51 def fix_camel_case(name): | |
| 52 refined = re.sub(r'-(\w)', lambda pat: pat.group(1).upper(), name) | |
| 53 refined = to_title_case(refined) | |
| 54 return re.sub(r'(?i)HTML|XML|WML|API', lambda pat: pat.group(0).upper(), ref
ined) | |
| 55 | |
| 56 | |
| 57 def to_title_case(name): | |
| 58 return name[:1].upper() + name[1:] | |
| 59 | |
| 60 | |
| 61 def generate_enum(name, json): | |
| 62 enum_members = [] | |
| 63 for member in json["enum"]: | |
| 64 enum_members.append(" %s: \"%s\"" % (fix_camel_case(member), member)) | |
| 65 return "\n/** @enum {string} */\n%s = {\n%s\n};\n" % (name, (",\n".join(enum
_members))) | |
| 66 | |
| 67 | |
| 68 def param_type(domain_name, param): | |
| 69 if "type" in param: | |
| 70 if param["type"] == "array": | |
| 71 items = param["items"] | |
| 72 return "Array.<%s>" % param_type(domain_name, items) | |
| 73 else: | |
| 74 return type_traits[param["type"]] | |
| 75 if "$ref" in param: | |
| 76 type_id = full_qualified_type_id(domain_name, param["$ref"]) | |
| 77 if type_id in ref_types: | |
| 78 return ref_types[type_id] | |
| 79 else: | |
| 80 print "Type not found: " + type_id | |
| 81 return "!! Type not found: " + type_id | |
| 82 | |
| 83 | |
| 84 def generate_protocol_externs(output_path, input_path): | |
| 85 input_file = open(input_path, "r") | |
| 86 json_string = input_file.read() | |
| 87 json_string = json_string.replace(": true", ": True") | |
| 88 json_string = json_string.replace(": false", ": False") | |
| 89 json_api = eval(json_string)["domains"] | |
| 90 | |
| 91 output_file = open(output_path, "w") | |
| 92 | |
| 93 output_file.write( | |
| 94 """ | |
| 95 var Protocol = {}; | |
| 96 /** @typedef {string}*/ | |
| 97 Protocol.Error; | |
| 98 """) | |
| 99 | |
| 100 for domain in json_api: | |
| 101 domain_name = domain["domain"] | |
| 102 if "types" in domain: | |
| 103 for type in domain["types"]: | |
| 104 type_id = full_qualified_type_id(domain_name, type["id"]) | |
| 105 ref_types[type_id] = "%sAgent.%s" % (domain_name, type["id"]) | |
| 106 | |
| 107 for domain in json_api: | |
| 108 domain_name = domain["domain"] | |
| 109 output_file.write("\n\n\nvar %sAgent = {};\n" % domain_name) | |
| 110 if "types" in domain: | |
| 111 for type in domain["types"]: | |
| 112 if type["type"] == "object": | |
| 113 typedef_args = [] | |
| 114 if "properties" in type: | |
| 115 for property in type["properties"]: | |
| 116 suffix = "" | |
| 117 if ("optional" in property): | |
| 118 suffix = "|undefined" | |
| 119 if "enum" in property: | |
| 120 enum_name = "%sAgent.%s%s" % (domain_name, type[
"id"], to_title_case(property["name"])) | |
| 121 output_file.write(generate_enum(enum_name, prope
rty)) | |
| 122 typedef_args.append("%s:(%s%s)" % (property["nam
e"], enum_name, suffix)) | |
| 123 else: | |
| 124 typedef_args.append("%s:(%s%s)" % (property["nam
e"], param_type(domain_name, property), suffix)) | |
| 125 if (typedef_args): | |
| 126 output_file.write("\n/** @typedef {{%s}|null} */\n%sAgen
t.%s;\n" % (", ".join(typedef_args), domain_name, type["id"])) | |
| 127 else: | |
| 128 output_file.write("\n/** @typedef {Object} */\n%sAgent.%
s;\n" % (domain_name, type["id"])) | |
| 129 elif type["type"] == "string" and "enum" in type: | |
| 130 output_file.write(generate_enum("%sAgent.%s" % (domain_name,
type["id"]), type)) | |
| 131 elif type["type"] == "array": | |
| 132 suffix = "" | |
| 133 if ("optional" in property): | |
| 134 suffix = "|undefined" | |
| 135 output_file.write("\n/** @typedef {Array.<%s>%s} */\n%sAgent
.%s;\n" % (param_type(domain_name, type["items"]), suffix, domain_name, type["id
"])) | |
| 136 else: | |
| 137 output_file.write("\n/** @typedef {%s} */\n%sAgent.%s;\n" %
(type_traits[type["type"]], domain_name, type["id"])) | |
| 138 | |
| 139 if "commands" in domain: | |
| 140 for command in domain["commands"]: | |
| 141 output_file.write("\n/**\n") | |
| 142 params = [] | |
| 143 if ("parameters" in command): | |
| 144 for in_param in command["parameters"]: | |
| 145 if ("optional" in in_param): | |
| 146 params.append("opt_%s" % in_param["name"]) | |
| 147 output_file.write(" * @param {%s=} opt_%s\n" % (para
m_type(domain_name, in_param), in_param["name"])) | |
| 148 else: | |
| 149 params.append(in_param["name"]) | |
| 150 output_file.write(" * @param {%s} %s\n" % (param_typ
e(domain_name, in_param), in_param["name"])) | |
| 151 returns = ["?Protocol.Error"] | |
| 152 if ("returns" in command): | |
| 153 for out_param in command["returns"]: | |
| 154 if ("optional" in out_param): | |
| 155 returns.append("%s=" % param_type(domain_name, out_p
aram)) | |
| 156 else: | |
| 157 returns.append("%s" % param_type(domain_name, out_pa
ram)) | |
| 158 output_file.write(" * @param {function(%s):void=} opt_callback\n
" % ", ".join(returns)) | |
| 159 output_file.write(" */\n") | |
| 160 params.append("opt_callback") | |
| 161 output_file.write("%sAgent.%s = function(%s) {}\n" % (domain_nam
e, command["name"], ", ".join(params))) | |
| 162 output_file.write("/** @param {function(%s):void=} opt_callback
*/\n" % ", ".join(returns)) | |
| 163 output_file.write("%sAgent.%s.invoke = function(obj, opt_callbac
k) {}\n" % (domain_name, command["name"])) | |
| 164 | |
| 165 output_file.write("/** @interface */\n") | |
| 166 output_file.write("%sAgent.Dispatcher = function() {};\n" % domain_name) | |
| 167 if "events" in domain: | |
| 168 for event in domain["events"]: | |
| 169 params = [] | |
| 170 if ("parameters" in event): | |
| 171 output_file.write("/**\n") | |
| 172 for param in event["parameters"]: | |
| 173 if ("optional" in param): | |
| 174 params.append("opt_%s" % param["name"]) | |
| 175 output_file.write(" * @param {%s=} opt_%s\n" % (para
m_type(domain_name, param), param["name"])) | |
| 176 else: | |
| 177 params.append(param["name"]) | |
| 178 output_file.write(" * @param {%s} %s\n" % (param_typ
e(domain_name, param), param["name"])) | |
| 179 output_file.write(" */\n") | |
| 180 output_file.write("%sAgent.Dispatcher.prototype.%s = function(%s
) {};\n" % (domain_name, event["name"], ", ".join(params))) | |
| 181 output_file.write("/**\n * @param {%sAgent.Dispatcher} dispatcher\n */\n
" % domain_name) | |
| 182 output_file.write("InspectorBackend.register%sDispatcher = function(disp
atcher) {}\n" % domain_name) | |
| 183 output_file.close() | |
| 184 | |
| 185 if __name__ == "__main__": | |
| 186 import sys | |
| 187 import os.path | |
| 188 program_name = os.path.basename(__file__) | |
| 189 if len(sys.argv) < 4 or sys.argv[1] != "-o": | |
| 190 sys.stderr.write("Usage: %s -o OUTPUT_FILE INPUT_FILE\n" % program_name) | |
| 191 exit(1) | |
| 192 output_path = sys.argv[2] | |
| 193 input_path = sys.argv[3] | |
| 194 generate_protocol_externs(output_path, input_path) | |
| OLD | NEW |