PageRenderTime 52ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/jsca2js.py

https://github.com/navinpeiris/jsca2js
Python | 275 lines | 235 code | 37 blank | 3 comment | 28 complexity | dd94c1ad3e7848df2d2adaeb0419717f MD5 | raw file
  1. #!/usr/bin/env python
  2. __author__ = "Navin Peiris"
  3. __copyright__ = "Copyright 2011, Navin Peiris. All rights reserved."
  4. __email__ = "navinpeiris@gmail.com"
  5. __status__ = "Development"
  6. import re
  7. from formatter import Formatter
  8. METHOD_INDENTATION = 4
  9. HTML_LINK_REGEX = '<a href=\"(.*?)\">(.*?)</a>'
  10. HTML_TARGET_SUFFIX = '.html'
  11. KEYS = {}
  12. def htmlToJsDocTarget(htmlTarget):
  13. if '-' in htmlTarget:
  14. return htmlTarget.partition('-')[0]
  15. if htmlTarget.endswith(HTML_TARGET_SUFFIX):
  16. return htmlTarget[0:-len(HTML_TARGET_SUFFIX)]
  17. return htmlTarget
  18. def createJsDocLink(target):
  19. return '{@link ' + target + '}'
  20. def convertLinks(jsDoc):
  21. result = jsDoc
  22. for linkMatcher in re.finditer(HTML_LINK_REGEX, jsDoc):
  23. htmlLink = linkMatcher.group(0)
  24. htmlTarget = linkMatcher.group(1)
  25. jsDocTarget = htmlToJsDocTarget(htmlTarget)
  26. jsDocLink = createJsDocLink(jsDocTarget)
  27. result = result.replace(htmlLink, jsDocLink)
  28. return result
  29. def convertIds(id):
  30. """ Converts invalid JavaScript identifiers to acceptable versions."""
  31. if id == 'default' or id == 'function':
  32. return '_' + id
  33. elif id.find('-') > 0:
  34. return id.replace('-', '_')
  35. return id
  36. def convertKey(id):
  37. """ Converts invalid JavaScript hash key to acceptable versions."""
  38. if id == 'default' or id.find('-') > 0:
  39. return '"' + id + '"'
  40. return id
  41. def getPlatforms(platforms):
  42. res = list()
  43. for platform in platforms:
  44. if type(platform) is dict:
  45. res.append(platform['pretty_name'])
  46. else:
  47. res.append(platform)
  48. return res
  49. def formatReturn(returns):
  50. typ = returns['type']
  51. if 'summary' in returns:
  52. return typ + ' ' + returns['summary']
  53. return typ
  54. def formatType(typeDef):
  55. if type(typeDef) is list:
  56. typ = '|'.join(typeDef)
  57. else:
  58. typ = typeDef
  59. return typ
  60. def formatSince(decl):
  61. if 'since' in decl:
  62. return decl['since']
  63. res = list()
  64. if 'platforms' in decl:
  65. for platform in decl['platforms']:
  66. res.append(platform['since'] + ' (' + platform['pretty_name'] + ')')
  67. else:
  68. return False
  69. return ', '.join(res)
  70. def generatePropertyJSDoc(property):
  71. formatter = Formatter(METHOD_INDENTATION)
  72. formatter.addLine('/**')
  73. prefix = ' * '
  74. if KEYS['value'] in property:
  75. formatter.addLine(prefix, property[KEYS['value']])
  76. if 'since' in property:
  77. formatter.addLine(prefix, 'platforms: ', ', '.join(getPlatforms(property['platforms'])))
  78. formatter.addLine(prefix, '@type ', formatType(property['type']))
  79. sinceVer = formatSince(property)
  80. if sinceVer:
  81. formatter.addLine(prefix, '@since ', sinceVer)
  82. formatter.addLine(' */')
  83. return convertLinks(formatter.getResult())
  84. def generateMethodJSDoc(method):
  85. formatter = Formatter(METHOD_INDENTATION)
  86. formatter.addLine('/**')
  87. prefix = ' * '
  88. if KEYS['value'] in method:
  89. formatter.addLine(prefix, method[KEYS['value']])
  90. if 'platforms' in method and 'since' in method:
  91. formatter.addLine(prefix, 'platforms: ', ', '.join(getPlatforms(method['platforms'])))
  92. for param in method['parameters']:
  93. formatter.addLine(prefix, '@param {', formatType(param['type']), '} ',
  94. convertIds(param['name']), ' ', (param[KEYS['description']] if KEYS['description'] in param else param['description'] ) or '')
  95. if 'returntype' in method and method['returntype'] == 'void':
  96. formatter.addLine(prefix, '@returns ', method['returntype'])
  97. elif 'returns' in method:
  98. returns = method['returns']
  99. if type(returns) is list:
  100. for ret in returns:
  101. if ret['type'] != 'void':
  102. formatter.addLine(prefix, '@returns ', formatReturn(ret))
  103. elif returns['type'] != 'void':
  104. formatter.addLine(prefix, '@returns ', formatReturn(returns))
  105. sinceVer = formatSince(method)
  106. if sinceVer:
  107. formatter.addLine(prefix, '@since ', sinceVer)
  108. formatter.addLine(' */')
  109. return convertLinks(formatter.getResult())
  110. def generateNamespaceJSDoc(namespace):
  111. formatter = Formatter()
  112. formatter.addLine('/**')
  113. prefix = ' * '
  114. if 'notes' in namespace and namespace['notes']:
  115. formatter.addLine(prefix, 'Notes: ', namespace['notes'])
  116. if 'platforms' in namespace:
  117. formatter.addLine(prefix, 'platforms: ', ', '.join(getPlatforms(namespace['platforms'])))
  118. if namespace['description']:
  119. formatter.addLine(prefix, '@namespace ', namespace['description'])
  120. if 'since' in namespace:
  121. formatter.addLine(prefix, '@since ', namespace['since'])
  122. if 'examples' in namespace:
  123. for example in namespace['examples']:
  124. formatter.addLine(prefix)
  125. formatter.addLine(prefix, '@example ', example['description'])
  126. formatter.addLine(prefix, example['code'])
  127. formatter.addLine(' */')
  128. return convertLinks(formatter.getResult())
  129. def formatParams(params):
  130. paramNames = [convertIds(param['name']) for param in params]
  131. return ', '.join(paramNames)
  132. def formatProperties(namespace):
  133. formatter = Formatter(METHOD_INDENTATION)
  134. for property in namespace['properties']:
  135. formatter.add(generatePropertyJSDoc(property))
  136. formatter.addLine(convertKey(property['name']), ':null,')
  137. formatter.newLine()
  138. return formatter.getResult()
  139. def formatMethods(namespace):
  140. formatter = Formatter(METHOD_INDENTATION)
  141. key = 'methods' if 'methods' in namespace else 'method'
  142. for method in namespace[key]:
  143. formatter.add(generateMethodJSDoc(method))
  144. formatter.addLine(convertKey(method['name']), ':function(', formatParams(method['parameters']), ") {")
  145. formatter.addLine('},')
  146. formatter.newLine()
  147. return formatter.getResult()
  148. def formatGlobal(namespace):
  149. formatter = Formatter(METHOD_INDENTATION)
  150. for method in namespace['methods']:
  151. formatter.add(generateMethodJSDoc(method))
  152. formatter.addLine('function ', convertKey(method['name']), '(', formatParams(method['parameters']), ") {")
  153. formatter.addLine('}')
  154. formatter.newLine()
  155. return formatter.getResult()
  156. def extendGlobal(name, namespace):
  157. formatter = Formatter(METHOD_INDENTATION)
  158. for method in namespace['methods']:
  159. formatter.add(generateMethodJSDoc(method))
  160. formatter.addLine(name, '.prototype.', convertKey(method['name']), ' = function(', formatParams(method['parameters']), ") {")
  161. formatter.addLine('};')
  162. formatter.newLine()
  163. return formatter.getResult()
  164. def formatNamespace(namespace):
  165. namespaceName = convertIds(namespace[0])
  166. namespaceContent = namespace[1]
  167. formatter = Formatter()
  168. formatter.add(generateNamespaceJSDoc(namespaceContent))
  169. if namespaceName.find('.') < 0:
  170. if namespaceName == 'Global': # ie. Global.alert -> alert()
  171. formatter.add(formatGlobal(namespaceContent))
  172. return formatter.getResult();
  173. formatter.add('var ')
  174. if namespaceName == 'Titanium':
  175. namespaceName = 'Ti'
  176. elif namespaceName.startswith('Global.'): # ie. Global.String prototype extension
  177. formatter.add(extendGlobal(namespaceName[7:], namespaceContent))
  178. return formatter.getResult();
  179. if 'subtype' in namespaceContent and namespaceContent['subtype'] == 'proxy':
  180. formatter.addLine(namespaceName, ' = function() {').addLine('};')
  181. formatter.addLine(namespaceName, '.prototype = {').newLine()
  182. else:
  183. formatter.addLine(namespaceName, ' = {').newLine()
  184. formatter.addLine(formatProperties(namespaceContent))
  185. formatter.addLine(formatMethods(namespaceContent))
  186. formatter.addLine('};').newLine()
  187. return formatter.getResult()
  188. def convertJsca2Js(jsca, version):
  189. version = '.'.join(version.split('.')[0:2])
  190. if float(version) >= 1.8:
  191. KEYS['value'] = 'summary'
  192. KEYS['description'] = 'summary'
  193. else:
  194. KEYS['value'] = 'value'
  195. KEYS['description'] = 'description'
  196. javascript = ''
  197. for namespace in sorted(jsca.items()):
  198. javascript += formatNamespace(namespace)
  199. javascript = javascript.replace('Titanium.', 'Ti.')
  200. javascript = javascript.replace('.2DMatrix', '.D2Matrix')
  201. javascript = javascript.replace('.3DMatrix', '.D3Matrix')
  202. javascript += "\nvar Titanium = Ti;\n"
  203. return javascript.replace(",\n\n\n}", "\n}")