generate_protocol_externs.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  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. import re
  30. type_traits = {
  31. "any": "*",
  32. "string": "string",
  33. "integer": "number",
  34. "number": "number",
  35. "boolean": "boolean",
  36. "array": "Array.<*>",
  37. "object": "Object",
  38. }
  39. ref_types = {}
  40. def full_qualified_type_id(domain_name, type_id):
  41. if type_id.find(".") == -1:
  42. return "%s.%s" % (domain_name, type_id)
  43. return type_id
  44. def fix_camel_case(name):
  45. refined = re.sub(r'-(\w)', lambda pat: pat.group(1).upper(), name)
  46. refined = to_title_case(refined)
  47. return re.sub(r'(?i)HTML|XML|WML|API', lambda pat: pat.group(0).upper(), refined)
  48. def to_title_case(name):
  49. return name[:1].upper() + name[1:]
  50. def generate_enum(name, json):
  51. enum_members = []
  52. for member in json["enum"]:
  53. enum_members.append(" %s: \"%s\"" % (fix_camel_case(member), member))
  54. return "\n/** @enum {string} */\n%s = {\n%s\n};\n" % (name, (",\n".join(enum_members)))
  55. def param_type(domain_name, param):
  56. if "type" in param:
  57. if param["type"] == "array":
  58. items = param["items"]
  59. return "Array.<%s>" % param_type(domain_name, items)
  60. else:
  61. return type_traits[param["type"]]
  62. if "$ref" in param:
  63. type_id = full_qualified_type_id(domain_name, param["$ref"])
  64. if type_id in ref_types:
  65. return ref_types[type_id]
  66. else:
  67. print "Type not found: " + type_id
  68. return "!! Type not found: " + type_id
  69. def generate_protocol_externs(output_path, input_path):
  70. input_file = open(input_path, "r")
  71. json_string = input_file.read()
  72. json_string = json_string.replace(": true", ": True")
  73. json_string = json_string.replace(": false", ": False")
  74. json_api = eval(json_string)["domains"]
  75. output_file = open(output_path, "w")
  76. output_file.write(
  77. """
  78. var Protocol = {};
  79. /** @typedef {string}*/
  80. Protocol.Error;
  81. """)
  82. for domain in json_api:
  83. domain_name = domain["domain"]
  84. if "types" in domain:
  85. for type in domain["types"]:
  86. type_id = full_qualified_type_id(domain_name, type["id"])
  87. ref_types[type_id] = "%sAgent.%s" % (domain_name, type["id"])
  88. for domain in json_api:
  89. domain_name = domain["domain"]
  90. output_file.write("\n\n\nvar %sAgent = {};\n" % domain_name)
  91. if "types" in domain:
  92. for type in domain["types"]:
  93. if type["type"] == "object":
  94. typedef_args = []
  95. if "properties" in type:
  96. for property in type["properties"]:
  97. suffix = ""
  98. if ("optional" in property):
  99. suffix = "|undefined"
  100. if "enum" in property:
  101. enum_name = "%sAgent.%s%s" % (domain_name, type["id"], to_title_case(property["name"]))
  102. output_file.write(generate_enum(enum_name, property))
  103. typedef_args.append("%s:(%s%s)" % (property["name"], enum_name, suffix))
  104. else:
  105. typedef_args.append("%s:(%s%s)" % (property["name"], param_type(domain_name, property), suffix))
  106. if (typedef_args):
  107. output_file.write("\n/** @typedef {{%s}|null} */\n%sAgent.%s;\n" % (", ".join(typedef_args), domain_name, type["id"]))
  108. else:
  109. output_file.write("\n/** @typedef {Object} */\n%sAgent.%s;\n" % (domain_name, type["id"]))
  110. elif type["type"] == "string" and "enum" in type:
  111. output_file.write(generate_enum("%sAgent.%s" % (domain_name, type["id"]), type))
  112. elif type["type"] == "array":
  113. suffix = ""
  114. if ("optional" in property):
  115. suffix = "|undefined"
  116. output_file.write("\n/** @typedef {Array.<%s>%s} */\n%sAgent.%s;\n" % (param_type(domain_name, type["items"]), suffix, domain_name, type["id"]))
  117. else:
  118. output_file.write("\n/** @typedef {%s} */\n%sAgent.%s;\n" % (type_traits[type["type"]], domain_name, type["id"]))
  119. if "commands" in domain:
  120. for command in domain["commands"]:
  121. output_file.write("\n/**\n")
  122. params = []
  123. if ("parameters" in command):
  124. for in_param in command["parameters"]:
  125. if ("optional" in in_param):
  126. params.append("opt_%s" % in_param["name"])
  127. output_file.write(" * @param {%s=} opt_%s\n" % (param_type(domain_name, in_param), in_param["name"]))
  128. else:
  129. params.append(in_param["name"])
  130. output_file.write(" * @param {%s} %s\n" % (param_type(domain_name, in_param), in_param["name"]))
  131. returns = ["?Protocol.Error"]
  132. if ("returns" in command):
  133. for out_param in command["returns"]:
  134. if ("optional" in out_param):
  135. returns.append("%s=" % param_type(domain_name, out_param))
  136. else:
  137. returns.append("%s" % param_type(domain_name, out_param))
  138. output_file.write(" * @param {function(%s):void=} opt_callback\n" % ", ".join(returns))
  139. output_file.write(" */\n")
  140. params.append("opt_callback")
  141. output_file.write("%sAgent.%s = function(%s) {}\n" % (domain_name, command["name"], ", ".join(params)))
  142. output_file.write("/** @param {function(%s):void=} opt_callback */\n" % ", ".join(returns))
  143. output_file.write("%sAgent.%s.invoke = function(obj, opt_callback) {}\n" % (domain_name, command["name"]))
  144. output_file.write("/** @interface */\n")
  145. output_file.write("%sAgent.Dispatcher = function() {};\n" % domain_name)
  146. if "events" in domain:
  147. for event in domain["events"]:
  148. params = []
  149. if ("parameters" in event):
  150. output_file.write("/**\n")
  151. for param in event["parameters"]:
  152. if ("optional" in param):
  153. params.append("opt_%s" % param["name"])
  154. output_file.write(" * @param {%s=} opt_%s\n" % (param_type(domain_name, param), param["name"]))
  155. else:
  156. params.append(param["name"])
  157. output_file.write(" * @param {%s} %s\n" % (param_type(domain_name, param), param["name"]))
  158. output_file.write(" */\n")
  159. output_file.write("%sAgent.Dispatcher.prototype.%s = function(%s) {};\n" % (domain_name, event["name"], ", ".join(params)))
  160. output_file.write("/**\n * @param {%sAgent.Dispatcher} dispatcher\n */\n" % domain_name)
  161. output_file.write("InspectorBackend.register%sDispatcher = function(dispatcher) {}\n" % domain_name)
  162. output_file.close()
  163. if __name__ == "__main__":
  164. import sys
  165. import os.path
  166. program_name = os.path.basename(__file__)
  167. if len(sys.argv) < 4 or sys.argv[1] != "-o":
  168. sys.stderr.write("Usage: %s -o OUTPUT_FILE INPUT_FILE\n" % program_name)
  169. exit(1)
  170. output_path = sys.argv[2]
  171. input_path = sys.argv[3]
  172. generate_protocol_externs(output_path, input_path)