/* JavaScript Development Utilities: Generically useful code for JavaScript development. http://sourceforge.net/projects/jsutil Copyright (C) 2003-2005, Jeff Epstein All rights reserved. Modifications: No Redistribution in binary form, with or without modifications, are permitted provided that the following conditions are met: * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * If modifications are made to source code then this license should indicate that fact in the "Modifications" section above. * Neither the author, nor the contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [NOTE: This license contains NO advertising clause.] */ package jsutil; import xbn.programs.XBNStatic; import xbn.XBNObject; import xbn.array.AOOValid; import xbn.array.AOOVCAll; import xbn.array.VWObject; import xbn.array.primitive.ListPA; import xbn.array.primitive.LPAConfig; import xbn.output.OWFile; import xbn.output.OSysDotOut; import xbn.string.SOBStringBuffer; import xbn.string.UtilChar; import xbn.string.UtilString; import xbn.template.GapConfig; import xbn.template.OGConfig; import xbn.template.Template; import xbn.template.TOGThree; import xbn.template.TOGTwo; import xbn.template.TemplateFiller; import xbn.template.util.GetTFFile; import xbn.template.util.GetTOG2FFile; import xbn.template.util.GetTOG3FFile; import xbn.template.util.GetTOGFrom; import xbn.util.FLRFile; import xbn.util.RCLength; import java.io.File; import java.util.StringTokenizer; /**

Generates JavaDoc-like documentation for a set of JavaScript code.

Source code:  GenerateJSDoc.java

Command line parameters

  1. The full path to the template directory. All templates but the 'overall' one must exist in this directory.
  2. The base path on which the relative paths in parameter three are based.
  3. A tokenized (by '///') list of relative paths to every JavaScript file you want to document. Must contain the ending '.js', and be properly formatted (as defined below). The order of this list is the order in which the table-of-contents is printed. If you need to provide a heck-of-a-lot of files (which DOS doesn't like), then set this alternatively to [[file=full_path_of_file]]. That file must contain each item on a separate line, with no blank lines. Line separator must equal System.getProperty("line.separator")
  4. The full path to the directory in which the documentation page for every item in parameter three is written to. Must be an existing and writeable directory. Existing files are overwritten.
  5. The full path to the final location of the overall template, containing the table-of-contents gap. Must exist, and contain at least the gap named in parameter six.
  6. The name of the table of contents gap that must exist in the overall template. It need not be the only gap, but this one at least must exist.
  7. The relative url from the overall template to the directory defined in parmeter four, including the final url slash ('/'). If not provided, then empty string ('') is assumed. Both this and eight must be either provided or not provided.
  8. The relative url from the directory defined in parmeter four, to the overall template, including the final url slash ('/'). If not provided, then empty string ('') is assumed. Both this and seven must be either provided or not provided.

Template-s

Every gap must be surrounded by \~G\~ and \~EG\~. For example:
   \~G\~all_toc_items\~EG\~

To display the tilde character ('\~') literally, use '\\\~'.

(example)   Overall

Must contain at least this one gap. May or may not contain others.

Gap Filled with
[The value of command-line parameter six] The accumulation of every 'JavaScript file table of contents item' Template result.

(example)   JavaScript file table of contents item (js_file_toc_item.tmpl)

Must contain exactly this set of unique gap names:

Gap Filled with
rurl_overall_to_js_dir The url to link from the table of contents page to the directory in which all JavaScript documentation files exist, including the final slash ('/'). This is the value of command-line parameter five, exactly as you provided.
js_file_no_post The name the JavaScript file, minus the '.js'.
js_summary The first full line of the JS FILE OVERVIEW DOCUMENTATION block for this JavaScript file.

(example)   JavaScript file overall (js_file.html)

Must contain exactly this set of unique gap names:

Gap Filled with
rurl_js_dir_to_overall The relative url from the JS-directory to the overall template. This is the value of parameter eight, exactly as provided.
js_file_no_post The name of the JavaScript file, excluding the '.js' postfix.
js_summary The first full line of the JS FILE OVERVIEW DOCUMENTATION block for this JavaScript file.
function_list Every function table of contents item, concatenated together.
js_description The entire contents of the JS FILE OVERVIEW DOCUMENTATION block.
all_function_sections Every function section, concatenated together.

(example)   Function toc entry (function_toc_item.tmpl)

Must contain exactly this set of unique gap names:

Gap Filled with
func_name The name of this function, minus parameters and parenthesis.
func_summary The first line of the PUBLIC FUNCTION block.

(example)   Function body (function_section.tmpl)

Must contain exactly this set of unique gap names:

Gap Filled with
js_file_no_post The name of the JavaScript file, excluding the '.js' postfix.
func_name The name of this function, minus parameters and parenthesis.
func_description The entire contents of the PUBLIC FUNCTION block.

Example

Assume these template files...

...and these JavaScript files:

Command line

First copy the overall template from source to destination:
   copy C:\\test_gjsdoc\\template\\index.html C:\\test_gjsdoc\\output\\index.html

And then:
   java jsutil.GenerateJSDoc C:\\test_gjsdoc\\template\\ C:\\test_gjsdoc\\js\\ util_string.js///utility.js///more_js\\util_array.js C:\\test_gjsdoc\\output\\ C:\\test_gjsdoc\\output\\index.html main_all_js_file_toc_items > C:\\test_gjsdoc\\output\\gjsdoc.log

Here is the final output and the log.

Technical details

State descriptions and key:

1
2   /**
3      PUBLIC FUNCTION
4
5      <P>A function summary line</P>
6      <P>Function documentation</P>
7    **/
8   function myFunction(with, parameters)  {
9   ...
10   }
11
12
13   /**
14      Some block we should ignore
15    **/
16
17
18   /**
19      JS FILE OVERVIEW DOCUMENTATION
20
21      <P>My OHD summary line</P>
22      <P>Overview doucemnation</P>
23    **/
24
25
26   /**
27      Another block we should ignore
28    **/
29
30
31
32   /**
33      PUBLIC FUNCTION
34
35      <P>A function summary line</P>
36      <P>Function documentation</P>
37    **/
38   function myFunction(with, a, whole,
39                       lot, of, parameters)&nbsp;
40   {
41   ...
42   }
43
44
45   /**
46      JS FILE OVERVIEW DOCUMENTATION
47
48      <P>My OHD summary line</P>
49      <P>Overview doucemnation</P>
50    **/
51
52
53   /**
54      PUBLIC FUNCTION
55
56      <P>A function only a summary line</P>
57    **/
58   function myFunction2(with, parameters)  {
59   ...
60   }
61
62
63   /**
64      Another block we should ignore
65    **/
66
67   

'x' means true, no value means 'false'

After line
analyzed
nov imlc iov ifn nsm nfg
1 x          
2-6 x x        
7-12 x          
13-14 x x        
15-17 x          
18 x x        
19-20 x x x   x  
21-22 x x x      
23-25            
26-27   x        
28-31            
32   x        
33-34   x   x x x
35-36   x   x   x
37           x
38-40           x
41-44            
45   x        
46-49   x        
50-52            
53   x        
54-55   x   x x x
56   x   x   x
57           x
58-62            
63-64   x        
65-67            
@version 0.9b @author Jeff Epstein, http://sourceforge.net/projects/jsutil. **/ public class GenerateJSDoc extends XBNStatic { private final static String sSNTYCHK = " SANITY CHECK. SHOULD NEVER HAPPEN"; private static final UtilString uString = new UtilString(); /**

The JavaScript file separator.

Equal to '///'

**/ public static String sJS_FILE_SEP = "///"; /**

The JavaScript file overview block marker

Equal to 'JS FILE OVERVIEW DOCUMENTATION'

**/ public static String sMRKR_OVERVIEW = "JS FILE OVERVIEW DOCUMENTATION"; /**

The Function block marker

Equal to 'PUBLIC FUNCTION'

**/ public static String sMRKR_FUNCTION = "PUBLIC FUNCTION"; /**

The multi-line comment start delimiter.

Equal to '/' + '**'**

**/ public static String sMLC_SLSH_STR_STR = "/" + "**"; /**

The multi-line comment end delimiter.

Equal to '**' + '/'

**/ public static String sMLC_STR_STR_SLSH = "**" + "/"; private static VWJSDoc vwjsd = new VWJSDoc(); private static boolean bInMLC = false; private static boolean bNeedOverviewBlock = true; private static boolean bInOverviewBlock = false; private static boolean bInFunctionBlock = false; private static boolean bNeedSummaryLine = false; private static boolean bNeedFuncSignature = false; private static int iLine = 0; private static int iLineMLC = 0; private static String sLTrmd = null; //For potential error diagnostics only private static SOBStringBuffer sobsbBlockBody = new SOBStringBuffer(""); private static String sSummaryLine = null; //For functions only: private static String sFuncName = null; public static void main(String[] as_cmdLineParams) { String sErrorRules = ".\n" + " - 1. The full path to the template directory. All templates but the 'overall' one must exist in this directory.\n" + " - 2. The base path on which the relative paths in parameter three are based.\n" + " - 3. A tokenized (by '" + sJS_FILE_SEP + "') list of relative paths to every JavaScript file you want to document. Must contain the ending '.js', and be properly formatted (as defined below). The order of this list is the order in which the table-of-contents is printed. For many-many-oh-so-many files, provide '[[file=**FULL_PATH_OF_FILE**]]'. That file must be line-delimited, and have no blank lines or whitespace.\n" + " - 4. The full path to the directory, including the final slash (" + File.separator + "), in which the documentation page for every item in parameter three is written to. Must be an existing and writeable directory. Existing files are overwritten.\n" + " - 5. The full path to the final location of the overall template, containing the table-of-contents gap. Must exist, and contain at least the gap named in parameter six.\n" + " - 6. The name of the table of contents gap that must exist in the overall template. It need not be the only gap, but this one at least must exist.\n" + " - 7. The relative url from the overall template to the directory defined in parmeter four, including the final url slash ('/'). If not provided, empty string ('') is assumed. Both this and eight must be either provided or not provided.\n" + " - 8. The relative url from the directory defined in parmeter four, to the overall template, including the final url slash ('/'). If not provided, empty string ('') is assumed. Both this and seven must be either provided or not provided.\n" + "\nActually provided command line (with " + as_cmdLineParams.length + " parameters):\njava jsutil.GenerateJSDoc " + (new ListPA(new LPAConfig(" "))).get(as_cmdLineParams); if(as_cmdLineParams.length < 6 || as_cmdLineParams.length == 7 || as_cmdLineParams.length > 8) { throwAXS("GenerateJSDoc: Wrong number of parameters provided" + sErrorRules); } String sTmplDir = as_cmdLineParams[0]; String sBasePath = as_cmdLineParams[1]; String sFileList = as_cmdLineParams[2]; String sOutputDir = as_cmdLineParams[3]; String sOverallDest = as_cmdLineParams[4]; String sTOCGap = as_cmdLineParams[5]; String sRelUrlOverall2JSDir = "";; String sRelUrlJSDir2Overall = "";; if(as_cmdLineParams.length == 8) { sRelUrlOverall2JSDir = as_cmdLineParams[6]; sRelUrlJSDir2Overall = as_cmdLineParams[7]; } if(sFileList.startsWith("[[file=")) { if(!sFileList.endsWith("]]")) { throwAXS("The file list (parameter 3) begins with '[[file=', but does not end with ']]'."); } //The file name sFileList = sFileList.substring("[[file=".length(), sFileList.length() - "]]".length()); sop("Reading in file list from '" + sFileList + "' ["); FLRFile flrf = new FLRFile(sFileList); //Now change sFileList to hold the value of the list. //It's no longer just the file name. SOBStringBuffer ssbFileList = new SOBStringBuffer(""); while(flrf.hasMoreLines()) { String sLine = flrf.getNextLine().toString(); ssbFileList.append(sLine.trim()); if(flrf.hasMoreLines()) { ssbFileList.append(sJS_FILE_SEP); } sop("."); } sFileList = ssbFileList.toString(); sopl("]"); } sopl("PARAMETERS:"); sopl(" 1 TMPL DIR '" + sTmplDir + "'"); sopl(" 2 BASE PATH '" + sBasePath + "'"); sopl(" 3 JS FILE LIST '" + sFileList + "'"); sopl(" 4 JSDOC PATH '" + sOutputDir + "'"); sopl(" 5 OVERALL TMPL '" + sOverallDest + "'"); sopl(" 6 TOC GAP '" + sTOCGap + "'"); sopl(" 7 REL URL O2JS '" + sRelUrlOverall2JSDir + "'"); sopl(" 8 REL URL JS20 '" + sRelUrlJSDir2Overall + "'"); sop("Actually provided command line (" + as_cmdLineParams.length + " parameters provided):\njava jsutil.GenerateJSDoc "); for(int i = 0; i < as_cmdLineParams.length; i++) { sop(as_cmdLineParams[i] + " "); } sopl(""); StringTokenizer stJSFiles = new StringTokenizer(sFileList, sJS_FILE_SEP); while(stJSFiles.hasMoreTokens()) { nlzJSFile(sBasePath, stJSFiles.nextToken().trim()); } //Now we have all the JavaScript files in memory. Print them out. GapConfig gc = new GapConfig(); OSysDotOut osdo = new OSysDotOut(); Template tOverall = (new GetTFFile("tOverall", sOverallDest, osdo)).getTemplate(); if(!tOverall.getAOSLHashtable().containsKey(sTOCGap)) { throwAXS("GenerateJSDoc: The overall template ('" + sOverallDest + "') must contain at least the gap named '" + sTOCGap + "' (as you provided for command line parameter SIX). All existing gaps: [" + tOverall.getListUnq(", ") + "]"); } TOGThree tog3JSFileTOCItem = (new GetTOG3FFile("tog3JSFileTOCItem", sTmplDir + "js_file_toc_item.tmpl", "rurl_overall_to_js_dir", "js_file_no_post", "js_summary", osdo)).getTOGThree(); Template tJSFile = (new GetTOGFrom("tJSFile", (new FLRFile(sTmplDir + "js_file.html")), new OGConfig( new String[] {"rurl_js_dir_to_overall", "js_file_no_post", "js_summary", "function_list", "js_description", "all_function_sections"}), gc, osdo)).getTemplate(); TOGTwo tog2FuncTOCItem = (new GetTOG2FFile("tog2FuncTOCItem", sTmplDir + "function_toc_item.tmpl", "func_name", "func_summary", osdo)).getTOGTwo(); Template tFuncSection = (new GetTOGFrom("tFuncSection", (new FLRFile(sTmplDir + "function_section.tmpl")), new OGConfig( new String[] {"js_file_no_post", "func_name", "func_description"}), gc, osdo)).getTemplate(); TemplateFiller tf = new TemplateFiller(false); tf.setOptrDbg(osdo); sopl("Outputting documentation..."); String sJSFileTOC = ""; for(int i = 0; i < vwjsd.getVector().size(); i++) { JSDoc jsd = vwjsd.getJSDoc(i); //Put this js file into the overall toc tf.setTemplate(tog3JSFileTOCItem); tf.fill("rurl_overall_to_js_dir", sRelUrlOverall2JSDir); tf.fill("js_file_no_post", jsd.getNameNoPost()); tf.fill("js_summary", jsd.getSummary()); sJSFileTOC += tf.getResult(); VWJSDocFunc vwjsdf = jsd.getVWJSDocFunc(); String sFuncTOC = ""; String sFuncSections = ""; for(int j = 0; j < vwjsdf.getVector().size(); j++) { JSDocFunc jsdf = vwjsdf.getJSDocFunc(j); tf.setTemplate(tog2FuncTOCItem); tf.fill("func_name", jsdf.getName()); tf.fill("func_summary", jsdf.getSummary()); sFuncTOC += tf.getResult(); tf.setTemplate(tFuncSection); tf.fill("func_name", jsdf.getName()); tf.fill("js_file_no_post", jsd.getNameNoPost()); tf.fill("func_description", jsdf.getHtmlBody()); sFuncSections += tf.getResult(); } tf.setTemplate(tJSFile); tf.fill("rurl_js_dir_to_overall", sRelUrlJSDir2Overall); tf.fill("js_file_no_post", jsd.getNameNoPost()); tf.fill("js_summary", jsd.getSummary()); tf.fill("function_list", sFuncTOC); tf.fill("js_description", jsd.getHtmlBody()); tf.fill("all_function_sections", sFuncSections); String sJSHtml = sOutputDir + jsd.getNameNoPost() + ".html"; sopl(" " + sJSHtml + "..."); (new OWFile(sJSHtml, false)).writeNoln(tf.getResult()); } tf.setTemplate(tOverall); tf.fill(sTOCGap, sJSFileTOC); String[] asGNYF = tf.getGapsNotYetFilled(); if(asGNYF != null) { for(int i = 0; i < asGNYF.length; i++) { tf.reGap(asGNYF[i]); } } sopl(" " + sOverallDest + "..."); (new OWFile(sOverallDest, false)).writeNoln(tf.getResult()); } private static void nlzJSFile(String s_basePath, String s_relJSFileNoPostfix) { FLRFile flrf = new FLRFile(s_basePath + s_relJSFileNoPostfix); //Initialize all state variables. bInMLC = false; bNeedOverviewBlock = true; bInOverviewBlock = false; bInFunctionBlock = false; bNeedSummaryLine = false; bNeedFuncSignature = false; iLine = 0; iLineMLC = 0; sobsbBlockBody.deleteAll(); while(flrf.hasMoreLines()) { StringBuffer sbLine = flrf.getNextLine(); sLTrmd = sbLine.toString().trim(); iLine++; if(!bInMLC) { //This line is not part of a multi-line comment... if(sLTrmd.equals(sMLC_SLSH_STR_STR)) { //...but the next line is bInMLC = true; //Ignore this line and go onto the next. continue; } //This is not an mlc line. The only thing, as far //as this program is concerned, is that it's not an //sMLC_STR_STR_SLSH if(sLTrmd.equals(sMLC_STR_STR_SLSH)) { throwAXGJSD(flrf.getFileName(), "This '" + sMLC_STR_STR_SLSH + "' ends a multi-line comment that was never begun"); } //This is a legal line outside of an mlc. if(bNeedFuncSignature) { //In fact, this is the very first line after an mlc. getFunctionSignature(flrf.getFileName()); bNeedFuncSignature = false; continue; } //This is a line we don't care about. continue; } //ELSE: // - bInMLC equals true *and* // - bNeedFuncSignature equals false // - This line does not equal sMLC_STR_STR_SLSH iLineMLC++; if(sLTrmd.equals(sMLC_STR_STR_SLSH)) { //This is the end of a multi-line comment. bInMLC = false; iLineMLC = 0; if(bInOverviewBlock) { //The overview block has been fully retrieved. //Store its values. addJSDoc( new JSDoc(s_basePath, s_relJSFileNoPostfix.substring(0, s_relJSFileNoPostfix.indexOf(".")), sSummaryLine, sobsbBlockBody.toString())); bInOverviewBlock = false; if(!bNeedOverviewBlock) { throwAXGJSD(flrf.getFileName(), "We're in the overview block, but we don't need it?!" + sSNTYCHK); } bNeedOverviewBlock = false; //...and initialize the temporary/state versions //of these values. sSummaryLine = null; sobsbBlockBody.deleteAll(); } else if(bInFunctionBlock) { //We're no longer in the function block... bInFunctionBlock = false; //...but we still need the function signature... if(!bNeedFuncSignature) { throwAXGJSD(flrf.getFileName(), "We just left a function block, but don't need the function signature?!" + sSNTYCHK); } //This function block has been fully retrieved, //but we still need the corresponding function //signature. } //Since we're not in a block or mlc anymore... iLineMLC = 0; //...and go onto the next line. continue; } //ELSE: // - bInMLC equals false *and* // - This line does not equal sMLC_STR_STR_SLSH *and* // - This line does not equal sMLC_SLSH_STR_STR // //This is a line somewhere between sMLC_SLSH_STR_STR //and sMLC_STR_STR_SLSH in the current multi-line //comment. We may have some more lines to retrieve. if(sLTrmd.equals(sMLC_SLSH_STR_STR)) { throwAXGJSD(flrf.getFileName(), "The '" + sMLC_SLSH_STR_STR + "' starts a multi-line comment before the previous one ended"); } //This is a valid line for the *middle* of a multi-line comment.. if(iLineMLC == 1) { //This is the first line after sMLC_SLSH_STR_STR, //in the multi-line comment. This is where the //marker must be... if(bNeedOverviewBlock) { //...and that marker is either the overview //marker (which we want and need and hope for) , //or a function marker (which we don't want and //need to ignore until the overview block is no //longer needed). if(sLTrmd.equals(sMRKR_OVERVIEW)) { bInOverviewBlock = true; bNeedSummaryLine = true; } //This is either the overview block, or a //plain-ol multi-line comment (which we want to //ignore) or a function block (which we want to //ignore). In any case, ignore this line and go //onto the next. continue; } //The overview block is no longer needed. Overview //markers are to be ignored. Function markers are //the ones that we want (ooh ooh ooh honey). if(sLTrmd.equals(sMRKR_FUNCTION)) { //This is a function marker. bInFunctionBlock = true; bNeedSummaryLine = true; bNeedFuncSignature = true; } //This is either a function block marker, or not. //Either way, this line is no longer needed. continue; } //ELSE: // - bInMLC equals false *and* // - This line does not equal sMLC_STR_STR_SLSH *and* // - This line does not equal sMLC_SLSH_STR_STR *and* // - This is not the first (marker) line in the mlc. // //This is the second or subsequent line in an mlc, //...which may or may not be a block. if(bInOverviewBlock || bInFunctionBlock) { //...which is also a block if(bNeedSummaryLine) { //The summary line has not yet been retrieved //for this block. if(sLTrmd.length() < 1) { //This line is whitespace only. Still need //to look for the summary line. continue; } //This line has some non-whitespace, and //therefore must be the summary line. It best //have at least one character between the //paragraph tags, too. if(sLTrmd.length() < "

".length()) { throwAXGJSD(flrf.getFileName(), "This is the summary line, which must start with '

' or '

', end with '

' or '

', and contain at least one character in those tags."); } //It has enough space for what's required. String sFirstThreeChars = sLTrmd.substring(0, "

".length()).toUpperCase(); String sLastThreeChars = sLTrmd.substring(sLTrmd.length() - "

".length()).toUpperCase(); if(sFirstThreeChars.equals("

") && sLastThreeChars.equals("

")) { //This is indeed the summary line. //Store the text between the paragraph tags //as the summary text. sSummaryLine = sLTrmd.substring("

".length(), sLTrmd.lastIndexOf("

")); //Put the summary line also into the body. //In the body, whitespace and the paragraph //tags should be preserved. Therefore, use //the untrimmed sbLine, rather than the //trimmed sLTrmd. sobsbBlockBody.append(sbLine.toString()); //We have the summary line. Go on to the //body of this block. bNeedSummaryLine = false; continue; } throwAXGJSD(flrf.getFileName(), "After the marker, this line is the first non-whitespace line in the block, but a summary line, after trim()-ming, must start with '

', end with '

' and contain at least one character between those paragraph tags."); } //We're in the body of the block, between the //summary line and sMLC_STR_STR_SLSH. Accumulate //the lines. Preserve the whitespace, so use the //untrimmed sbLine, rather than the trimmed sLTrmd. sobsbBlockBody.append(sbLine.toString()); continue; } //ELSE: // - bInMLC equals false *and* // - This line does not equal sMLC_STR_STR_SLSH *and* // - This line does not equal sMLC_SLSH_STR_STR *and* // - This is not the first (marker) line in the mlc *and* // - This is any line at all within an mlc or block. } if(bNeedOverviewBlock) { throwAXGJSD(flrf.getFileName(), "The end of the file has been reached, but no overview block exists"); } if(vwjsd.getJSDoc(vwjsd.getVector().size() - 1).getVWJSDocFunc().getVector().size() < 1) { throwAXGJSD(flrf.getFileName(), "No public function blocks in this JavaScript file."); } } private static final void getFunctionSignature(String s_fileName) { //This is the first line after a funciton block, //where the function signature must be. final String sFNC = "function"; if(!sLTrmd.startsWith(sFNC)) { throwAXGJSD(s_fileName, "The first line after the function block must contain the function signature"); } //This is the (first line in the) function //signature. It must start //'function myFunction(' char cAfterFunction = sLTrmd.charAt(sFNC.length()); if(cAfterFunction != ' ' && cAfterFunction != '\t') { throwAXGJSD(s_fileName, "The first character after 'function' must be a tab or space "); } int iIdxParenO = sLTrmd.indexOf("("); if(iIdxParenO == -1) { throwAXGJSD(s_fileName, "The first line of a function signature must contain at least 'function myFunction('"); } //The function name must be between (that //tab/space after) 'function' and the open //paren. sFuncName = sLTrmd.substring((sFNC.length() + 1), iIdxParenO).trim(); if(sFuncName.length() < 1) { throwAXGJSD(s_fileName, "The is no function name between 'function' and the open paren ('(')."); } if(!uString.isLetterDigitUnderscore(sFuncName) && uString.hasLettersOrInAOC(sFuncName.substring(0, 1), false, new char[] {'_'})) { throwAXGJSD(s_fileName, "The function name's first character must start with a letter or underscore. The rest must be letters, digits, or underscores."); } //Store the values... JSDoc jsd = vwjsd.getJSDoc(vwjsd.getVector().size() - 1); jsd.addJSDocFunc( new JSDocFunc(sFuncName, sSummaryLine, sobsbBlockBody.toString())); //...and initialize the temporary/state versions //of these values. sFuncName = null; sSummaryLine = null; sobsbBlockBody.deleteAll(); } private static final String getStatus(int i_dbgCounter) { String sStatus = i_dbgCounter + " [" + iLine + "/" + iLineMLC + "] "; if(bInMLC) { sStatus += "imlc "; } else { sStatus += " "; } if(bNeedOverviewBlock) { sStatus += "nov "; } else { sStatus += " "; } if(bInOverviewBlock) { sStatus += "iov "; } else { sStatus += " "; } if(bInFunctionBlock) { sStatus += "ifn "; } else { sStatus += " "; } if(bNeedSummaryLine) { sStatus += "nsm "; } else { sStatus += " "; } if(bNeedFuncSignature) { sStatus += "nfg "; } else { sStatus += " "; } return sStatus; } private static final void throwAXGJSD(String s_fileName, String s_message) { String sDiagnostics = ". Diagnostics:\n\t" + "JS FILE: '" + s_fileName + "'\n\t" + "iLine=" + iLine + "\n\t" + "iLineMLC=" + iLineMLC + "\n\t" + "bInMLC=" + bInMLC + "\n\t" + "bNeedOverviewBlock=" + bNeedOverviewBlock + "\n\t" + "bInOverviewBlock=" + bInOverviewBlock + "\n\t" + "bInFunctionBlock=" + bInFunctionBlock + "\n\t" + "bNeedSummaryLine=" + bNeedSummaryLine + "\n\t" + "bNeedFuncSignature=" + bNeedFuncSignature + "\n\t" + "iLine=" + iLine + "\n\t" + "iLineMLC=" + iLineMLC + "\n\t" + "sLTrmd='" + sLTrmd + "'\n\t" + "sSummaryLine='" + sSummaryLine + "'\n\t" + "sFuncName='" + sFuncName + "'\n\t" + "sobsbBlockBody=[" + sobsbBlockBody.toString() + "]"; throwAXS("GenerateJSDoc: " + s_message + sDiagnostics); } private static void addJSDoc(JSDoc js_doc) { if(js_doc == null) { throwAXS("GenerateJSDoc.addJSDoc: js_doc is null."); } vwjsd.addJSDoc(js_doc); } } class JSDoc extends XBNObject { private String sBasePath = null; private String sRelJSFile = null; private String sNameNoPost = null; private String sSummary = null; private String sHtmlBody = null; private VWJSDocFunc vwjsdf = new VWJSDocFunc(); //This class is not static, but I know it's going to be created one-at-a-time. // private static final AOOValid aoov = new AOOValid( // new AOOVCAll( // new RCLength(1))); // aoov.crashIfBad(this.getClass().getNameNoPost() + ".constructor", "a_jsdFunc", a_jsdFunc); /**

The name of this JSDoc is everything following the final File.separator in s_relJSFileNoPostfix,

**/ public JSDoc(String s_basePath, String s_relJSFileNoPostfix, String s_ummaryLine, String s_postSmryHtml) { throwAXIfBadStr(s_basePath, "s_basePath", "constructor"); throwAXIfBadStr(s_relJSFileNoPostfix, "s_relJSFileNoPostfix", "constructor"); throwAXIfBadStr(s_ummaryLine, "s_ummaryLine", "constructor"); throwAXIfBadStr(s_postSmryHtml, "s_postSmryHtml", "constructor"); if(s_relJSFileNoPostfix.indexOf(".") != -1) { throwAX("constructor: s_relJSFileNoPostfix ('" + s_relJSFileNoPostfix + "') may not contain a dot ('.')."); } sBasePath = s_basePath; if(s_relJSFileNoPostfix.indexOf(File.separator) == -1) { sNameNoPost = s_relJSFileNoPostfix; } else { sNameNoPost = s_relJSFileNoPostfix.substring( (s_relJSFileNoPostfix.lastIndexOf(File.separator) + 1), s_relJSFileNoPostfix.length()); } sRelJSFile = s_relJSFileNoPostfix; sSummary = s_ummaryLine; sHtmlBody = s_postSmryHtml; sopl(sNameNoPost); } public void addJSDocFunc(JSDocFunc jsd_func) { throwAXIfNull(jsd_func, "jsd_func", "addJSDocFunc"); vwjsdf.addJSDocFunc(jsd_func); } public String getBasePath() { return sBasePath; } public String getRelJSFile() { return sRelJSFile; } public String getNameNoPost() { return sNameNoPost; } public String getSummary() { return sSummary; } public String getHtmlBody() { return sHtmlBody; } public VWJSDocFunc getVWJSDocFunc() { return vwjsdf; } public final String toString() { String sTs = "getBasePath()='" + getBasePath() + "'\n\t" + "getRelJSFile()='" + getRelJSFile() + "'\n\t" + "getNameNoPost()='" + getNameNoPost() + "'\n\t" + "getNameNoPost()='" + getNameNoPost() + "', " + "getSummary()='" + getSummary() + "'\n\t" + "getHtmlBody()=[" + getHtmlBody() + "]\n\t" + "getVWJSDocFunc()={"; for(int i = 0; i < getVWJSDocFunc().getVector().size(); i++) { if(i > 0) { sTs += ", "; } sTs += "[" + i + ": " + getVWJSDocFunc().getJSDocFunc(i).toString() + "]"; } sTs += "}"; return sTs; } } class JSDocFunc extends XBNObject { private String sName = null; private String sSummary = null; private String sHtmlBody = null; public JSDocFunc(String s_name, String s_ummaryLine, String s_postSmryHtml) { throwAXIfBadStr(s_name, "s_name", "constructor"); throwAXIfBadStr(s_ummaryLine, "s_ummaryLine", "constructor"); throwAXIfBadStr(s_postSmryHtml, "s_postSmryHtml", "constructor"); sName = s_name; sSummary = s_ummaryLine; sHtmlBody = s_postSmryHtml; sopl(" " + sName); } public String getName() { return sName; } public String getSummary() { return sSummary; } public String getHtmlBody() { return sHtmlBody; } public final String toString() { return "getName()='" + getName() + "', " + "getSummary()='" + getSummary() + "', " + "getHtmlBody()=[" + getHtmlBody() + "]"; } } class VWJSDocFunc extends VWObject { public final JSDocFunc[] getAOJSDocFunc() { Object[] ao = getAOObject(); if(ao == null) { return null; } if(ao.length == 0) { return (new JSDocFunc[0]); } //The array is at least one element in length. JSDocFunc[] aJSDocFunc = new JSDocFunc[ao.length]; for(int i = 0; i < aJSDocFunc.length; i++) { aJSDocFunc[i] = (JSDocFunc)ao[i]; } return aJSDocFunc; } public final JSDocFunc getJSDocFunc(int i_dx) { return (JSDocFunc)getObject(i_dx); } public final void addJSDocFunc(JSDocFunc jsd_func) { add(jsd_func); } } class VWJSDoc extends VWObject { public final JSDoc[] getAOJSDoc() { Object[] ao = getAOObject(); if(ao == null) { return null; } if(ao.length == 0) { return (new JSDoc[0]); } //The array is at least one element in length. JSDoc[] aJSDoc = new JSDoc[ao.length]; for(int i = 0; i < aJSDoc.length; i++) { aJSDoc[i] = (JSDoc)ao[i]; } return aJSDoc; } public final JSDoc getJSDoc(int i_dx) { return (JSDoc)getObject(i_dx); } public final void addJSDoc(JSDoc js_doc) { add(js_doc); } }