doc/tools/pyjsrest.py
changeset 5470 fb004819cab4
child 6880 4be32427b2b9
equal deleted inserted replaced
5468:7199fddc0a88 5470:fb004819cab4
       
     1 #!/usr/bin/env python
       
     2 """
       
     3 Parser for Javascript comments.
       
     4 """
       
     5 from __future__ import with_statement
       
     6 
       
     7 import sys, os, getopt, re
       
     8 
       
     9 def clean_comment(match):
       
    10     comment = match.group()
       
    11     comment = strip_stars(comment)
       
    12     return comment
       
    13 
       
    14 # Rest utilities
       
    15 def rest_title(title, level, level_markups=['=', '=', '-', '~', '+', '`']):
       
    16     size = len(title)
       
    17     if level == 0:
       
    18         return '\n'.join((level_markups[level] * size, title, level_markups[0] * size)) + '\n'
       
    19     return '\n'.join(('\n' + title, level_markups[level] * size)) + '\n'
       
    20 
       
    21 def get_doc_comments(text):
       
    22     """
       
    23     Return a list of all documentation comments in the file text.  Each
       
    24     comment is a pair, with the first element being the comment text and
       
    25     the second element being the line after it, which may be needed to
       
    26     guess function & arguments.
       
    27 
       
    28     >>> get_doc_comments(read_file('examples/module.js'))[0][0][:40]
       
    29     '/**\n * This is the module documentation.'
       
    30     >>> get_doc_comments(read_file('examples/module.js'))[1][0][7:50]
       
    31     'This is documentation for the first method.'
       
    32     >>> get_doc_comments(read_file('examples/module.js'))[1][1]
       
    33     'function the_first_function(arg1, arg2) '
       
    34     >>> get_doc_comments(read_file('examples/module.js'))[2][0]
       
    35     '/** This is the documentation for the second function. */'
       
    36 
       
    37     """
       
    38     return [clean_comment(match) for match in re.finditer('/\*\*.*?\*/',
       
    39             text, re.DOTALL|re.MULTILINE)]
       
    40 
       
    41 RE_STARS = re.compile('^\s*?\* ?', re.MULTILINE)
       
    42 
       
    43 
       
    44 def strip_stars(doc_comment):
       
    45     """
       
    46     Strip leading stars from a doc comment.
       
    47 
       
    48     >>> strip_stars('/** This is a comment. */')
       
    49     'This is a comment.'
       
    50     >>> strip_stars('/**\n * This is a\n * multiline comment. */')
       
    51     'This is a\n multiline comment.'
       
    52     >>> strip_stars('/** \n\t * This is a\n\t * multiline comment. \n*/')
       
    53     'This is a\n multiline comment.'
       
    54 
       
    55     """
       
    56     return RE_STARS.sub('', doc_comment[3:-2]).strip()
       
    57 
       
    58 def parse_js_files(args=sys.argv):
       
    59     """
       
    60     Main command-line invocation.
       
    61     """
       
    62     try:
       
    63         opts, args = getopt.gnu_getopt(args[1:], 'p:o:h', [
       
    64             'jspath=', 'output=', 'help'])
       
    65         opts = dict(opts)
       
    66     except getopt.GetoptError:
       
    67         usage()
       
    68         sys.exit(2)
       
    69 
       
    70     rst_dir = opts.get('--output') or opts.get('-o')
       
    71     if rst_dir is None and len(args) != 1:
       
    72         rst_dir = 'apidocs'
       
    73     js_dir = opts.get('--jspath') or opts.get('-p')
       
    74     if not os.path.exists(os.path.join(rst_dir)):
       
    75         os.makedirs(os.path.join(rst_dir))
       
    76 
       
    77     f_index = open(os.path.join(rst_dir, 'index.rst'), 'wb')
       
    78     f_index.write('''
       
    79 .. toctree::
       
    80     :maxdepth: 1
       
    81 
       
    82 '''
       
    83 )
       
    84     for js_path, js_dirs, js_files in os.walk(js_dir):
       
    85         rst_path = re.sub('%s%s*' % (js_dir, os.path.sep), '', js_path)
       
    86         for js_file in js_files:
       
    87             if not js_file.endswith('.js'):
       
    88                 continue
       
    89             if not os.path.exists(os.path.join(rst_dir, rst_path)):
       
    90                 os.makedirs(os.path.join(rst_dir, rst_path))
       
    91             rst_content =  extract_rest(js_path, js_file)
       
    92             filename = os.path.join(rst_path, js_file[:-3])
       
    93             # add to index
       
    94             f_index.write('    %s\n' % filename)
       
    95             # save rst file
       
    96             with open(os.path.join(rst_dir, filename) + '.rst', 'wb') as f_rst:
       
    97                 f_rst.write(rst_content)
       
    98     f_index.close()
       
    99 
       
   100 def extract_rest(js_dir, js_file):
       
   101     js_filepath = os.path.join(js_dir, js_file)
       
   102     filecontent = open(js_filepath, 'U').read()
       
   103     comments = get_doc_comments(filecontent)
       
   104     rst = rest_title(js_file, 0)
       
   105     rst += '.. module:: %s\n\n' % js_file
       
   106     rst += '\n\n'.join(comments)
       
   107     return rst
       
   108 
       
   109 if __name__ == '__main__':
       
   110     parse_js_files()