doc/tools/pyjsrest.py
changeset 5470 fb004819cab4
child 6880 4be32427b2b9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tools/pyjsrest.py	Wed May 05 16:44:02 2010 +0200
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+"""
+Parser for Javascript comments.
+"""
+from __future__ import with_statement
+
+import sys, os, getopt, re
+
+def clean_comment(match):
+    comment = match.group()
+    comment = strip_stars(comment)
+    return comment
+
+# Rest utilities
+def rest_title(title, level, level_markups=['=', '=', '-', '~', '+', '`']):
+    size = len(title)
+    if level == 0:
+        return '\n'.join((level_markups[level] * size, title, level_markups[0] * size)) + '\n'
+    return '\n'.join(('\n' + title, level_markups[level] * size)) + '\n'
+
+def get_doc_comments(text):
+    """
+    Return a list of all documentation comments in the file text.  Each
+    comment is a pair, with the first element being the comment text and
+    the second element being the line after it, which may be needed to
+    guess function & arguments.
+
+    >>> get_doc_comments(read_file('examples/module.js'))[0][0][:40]
+    '/**\n * This is the module documentation.'
+    >>> get_doc_comments(read_file('examples/module.js'))[1][0][7:50]
+    'This is documentation for the first method.'
+    >>> get_doc_comments(read_file('examples/module.js'))[1][1]
+    'function the_first_function(arg1, arg2) '
+    >>> get_doc_comments(read_file('examples/module.js'))[2][0]
+    '/** This is the documentation for the second function. */'
+
+    """
+    return [clean_comment(match) for match in re.finditer('/\*\*.*?\*/',
+            text, re.DOTALL|re.MULTILINE)]
+
+RE_STARS = re.compile('^\s*?\* ?', re.MULTILINE)
+
+
+def strip_stars(doc_comment):
+    """
+    Strip leading stars from a doc comment.
+
+    >>> strip_stars('/** This is a comment. */')
+    'This is a comment.'
+    >>> strip_stars('/**\n * This is a\n * multiline comment. */')
+    'This is a\n multiline comment.'
+    >>> strip_stars('/** \n\t * This is a\n\t * multiline comment. \n*/')
+    'This is a\n multiline comment.'
+
+    """
+    return RE_STARS.sub('', doc_comment[3:-2]).strip()
+
+def parse_js_files(args=sys.argv):
+    """
+    Main command-line invocation.
+    """
+    try:
+        opts, args = getopt.gnu_getopt(args[1:], 'p:o:h', [
+            'jspath=', 'output=', 'help'])
+        opts = dict(opts)
+    except getopt.GetoptError:
+        usage()
+        sys.exit(2)
+
+    rst_dir = opts.get('--output') or opts.get('-o')
+    if rst_dir is None and len(args) != 1:
+        rst_dir = 'apidocs'
+    js_dir = opts.get('--jspath') or opts.get('-p')
+    if not os.path.exists(os.path.join(rst_dir)):
+        os.makedirs(os.path.join(rst_dir))
+
+    f_index = open(os.path.join(rst_dir, 'index.rst'), 'wb')
+    f_index.write('''
+.. toctree::
+    :maxdepth: 1
+
+'''
+)
+    for js_path, js_dirs, js_files in os.walk(js_dir):
+        rst_path = re.sub('%s%s*' % (js_dir, os.path.sep), '', js_path)
+        for js_file in js_files:
+            if not js_file.endswith('.js'):
+                continue
+            if not os.path.exists(os.path.join(rst_dir, rst_path)):
+                os.makedirs(os.path.join(rst_dir, rst_path))
+            rst_content =  extract_rest(js_path, js_file)
+            filename = os.path.join(rst_path, js_file[:-3])
+            # add to index
+            f_index.write('    %s\n' % filename)
+            # save rst file
+            with open(os.path.join(rst_dir, filename) + '.rst', 'wb') as f_rst:
+                f_rst.write(rst_content)
+    f_index.close()
+
+def extract_rest(js_dir, js_file):
+    js_filepath = os.path.join(js_dir, js_file)
+    filecontent = open(js_filepath, 'U').read()
+    comments = get_doc_comments(filecontent)
+    rst = rest_title(js_file, 0)
+    rst += '.. module:: %s\n\n' % js_file
+    rst += '\n\n'.join(comments)
+    return rst
+
+if __name__ == '__main__':
+    parse_js_files()