#!/usr/bin/env python"""Parser for Javascript comments."""importos.pathasospimportsys,os,getopt,redefclean_comment(match):comment=match.group()comment=strip_stars(comment)returncomment# Rest utilitiesdefrest_title(title,level,level_markups=['=','=','-','~','+','`']):size=len(title)iflevel==0:return'\n'.join((level_markups[level]*size,title,level_markups[0]*size))+'\n'return'\n'.join(('\n'+title,level_markups[level]*size))+'\n'defget_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)formatchinre.finditer('/\*\*.*?\*/',text,re.DOTALL|re.MULTILINE)]RE_STARS=re.compile('^\s*?\* ?',re.MULTILINE)defstrip_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.' """returnRE_STARS.sub('',doc_comment[3:-2]).strip()defparse_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)exceptgetopt.GetoptError:usage()sys.exit(2)rst_dir=opts.get('--output')oropts.get('-o')ifrst_dirisNoneandlen(args)!=1:rst_dir='apidocs'js_dir=opts.get('--jspath')oropts.get('-p')ifnotosp.exists(osp.join(rst_dir)):os.makedirs(osp.join(rst_dir))index=set()forjs_path,js_dirs,js_filesinos.walk(js_dir):rst_path=re.sub('%s%s*'%(js_dir,osp.sep),'',js_path)forjs_fileinjs_files:ifnotjs_file.endswith('.js'):continueifjs_fileinFILES_TO_IGNORE:continueifnotosp.exists(osp.join(rst_dir,rst_path)):os.makedirs(osp.join(rst_dir,rst_path))rst_content=extract_rest(js_path,js_file)filename=osp.join(rst_path,js_file[:-3])# add to indexindex.add(filename)# save rst filewithopen(osp.join(rst_dir,filename)+'.rst','wb')asf_rst:f_rst.write(rst_content.encode())stream=open(osp.join(rst_dir,'index.rst'),'w')stream.write('''Javascript API==============.. toctree:: :maxdepth: 1''')# first write expected files in orderforfileidinINDEX_IN_ORDER:try:index.remove(fileid)exceptException:raiseException('Bad file id %s referenced in INDEX_IN_ORDER in %s, ''fix this please'%(fileid,__file__))stream.write(' %s\n'%fileid)# append remaining, by alphabetical orderforfileidinsorted(index):stream.write(' %s\n'%fileid)stream.close()defextract_rest(js_dir,js_file):js_filepath=osp.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_filerst+='\n\n'.join(comments)returnrstINDEX_IN_ORDER=['cubicweb','cubicweb.python','cubicweb.htmlhelpers','cubicweb.ajax','cubicweb.ajax.box','cubicweb.facets','cubicweb.widgets','cubicweb.image','cubicweb.flot','cubicweb.calendar','cubicweb.preferences','cubicweb.edition','cubicweb.reledit',]FILES_TO_IGNORE=set(['jquery.js','jquery.treeview.js','jquery.tablesorter.js','jquery.timePicker.js','jquery.flot.js','jquery.corner.js','jquery.ui.js','excanvas.js','gmap.utility.labeledmarker.js','cubicweb.fckcwconfig.js','cubicweb.fckcwconfig-full.js','cubicweb.compat.js',])if__name__=='__main__':parse_js_files()