зеркало из https://github.com/mozilla/pjs.git
554 строки
16 KiB
JavaScript
554 строки
16 KiB
JavaScript
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is Rhino code, released
|
|
* May 6, 1999.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Norris Boyd
|
|
* Roland Pennings
|
|
*
|
|
* Alternatively, the contents of this file may be used under the
|
|
* terms of the GNU Public License (the "GPL"), in which case the
|
|
* provisions of the GPL are applicable instead of those above.
|
|
* If you wish to allow use of your version of this file only
|
|
* under the terms of the GPL and not to allow others to use your
|
|
* version of this file under the NPL, indicate your decision by
|
|
* deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this
|
|
* file under either the NPL or the GPL.
|
|
*/
|
|
|
|
/**
|
|
* Process a JavaScript source file and process special comments
|
|
* to produce an HTML file of documentation, similar to javadoc.
|
|
* @author Norris Boyd
|
|
* @see rhinotip.jar
|
|
* @lastmodified xx
|
|
* @version 1.2 Roland Pennings: Allow multiple files for a function.
|
|
* @version 1.3 Roland Pennings: Removes ../.. from the input directory name
|
|
*/
|
|
defineClass("File")
|
|
|
|
var functionDocArray = [];
|
|
var inputDirName = "";
|
|
var indexFileArray = [];
|
|
var indexFile = "";
|
|
var indexFileName = "index_files";
|
|
var indexFunctionArray = [];
|
|
var indexFunction = "";
|
|
var indexFunctionName = "index_functions";
|
|
var FileList = [];
|
|
var DirList = [];
|
|
var outputdir = null;
|
|
var debug = 0;
|
|
|
|
|
|
|
|
/**
|
|
* Process JavaScript source file <code>f</code>, writing jsdoc to
|
|
* file <code>out</code>.
|
|
* @param f input file
|
|
* @param fname name of the input file (without the path)
|
|
* @param inputdir directory of the input file
|
|
* @param out output file
|
|
*/
|
|
function processFile(f, fname, inputdir, out) {
|
|
var s;
|
|
var firstLine = true;
|
|
indexFileArray[fname] = "";
|
|
|
|
// write the header of the output file
|
|
out.writeLine('<HTML><HEADER><TITLE>' + fname + '</TITLE><BODY>');
|
|
if (inputdir != null) {
|
|
outstr = '<a name=\"_top_\"></a><pre><a href=\"' + indexFile + '\">Index Files</a> ';
|
|
outstr += '<a href=\"' + indexFunction + '\">Index Functions</a></pre><hr>';
|
|
out.writeLine(outstr);
|
|
}
|
|
|
|
// process the input file
|
|
var comment = "";
|
|
while ((s = f.readLine()) != null) {
|
|
var m = s.match(/\/\*\*(.*)/);
|
|
if (m != null) {
|
|
// Found a comment start.
|
|
s = "*" + m[1];
|
|
do {
|
|
m = s.match(/(.*)\*\//);
|
|
if (m != null) {
|
|
// Found end of comment.
|
|
comment += m[1];
|
|
break;
|
|
}
|
|
// Strip leading whitespace and "*".
|
|
comment += s.replace(/^\s*\*/, "");
|
|
s = f.readLine();
|
|
} while (s != null);
|
|
|
|
if (debug)
|
|
print("Found comment " + comment);
|
|
|
|
if (firstLine) {
|
|
// We have a comment for the whole file.
|
|
out.writeLine('<H1>File ' + fname + '</H1>');
|
|
out.writeLine(processComment(comment,firstLine,fname));
|
|
out.writeLine('<HR>');
|
|
firstLine = false;
|
|
comment = "";
|
|
continue;
|
|
}
|
|
}
|
|
// match the beginning of the function
|
|
// NB we also match functions without a comment!
|
|
// if we have two comments one after another only the last one will be taken
|
|
m = s.match(/^\s*function\s+((\w+)|(\w+)(\s+))\(([^)]*)\)/);
|
|
if (m != null)
|
|
{
|
|
// Found a function start
|
|
var htmlText = processFunction(m[1], m[5], comment); // sjm changed from 2nd to 5th arg
|
|
|
|
// Save the text in a global variable, so we
|
|
// can write out a table of contents first.
|
|
functionDocArray[functionDocArray.length] = {name:m[1], text:htmlText};
|
|
|
|
// Store the function also in the indexFunctionArray
|
|
// so we can have a seperate file with the function table of contents
|
|
if (indexFunctionArray[m[1]]) {
|
|
// print("ERROR: function: " + m[1] + " is defined more than once!");
|
|
// Allow multiple files for a function
|
|
with (indexFunctionArray[m[1]]) {
|
|
filename = filename + "|" + fname;
|
|
// print("filename = " + filename);
|
|
}
|
|
}
|
|
else {
|
|
indexFunctionArray[m[1]] = {filename:fname};
|
|
}
|
|
//reset comment
|
|
comment = "";
|
|
}
|
|
// match a method being bound to a prototype
|
|
m = s.match(/^\s*(\w*)\.prototype\.(\w*)\s*=\s*function\s*\(([^)]*)\)/);
|
|
if (m != null)
|
|
{
|
|
// Found a method being bound to a prototype.
|
|
var htmlText = processPrototypeMethod(m[1], m[2], m[3], comment);
|
|
|
|
// Save the text in a global variable, so we
|
|
// can write out a table of contents first.
|
|
functionDocArray[functionDocArray.length] = {name:m[1]+".prototype."+m[2], text:htmlText};
|
|
|
|
// Store the function also in the indexFunctionArray
|
|
// so we can have a seperate file with the function table of contents
|
|
if (indexFunctionArray[m[1]]) {
|
|
// print("ERROR: function: " + m[1] + " is defined more than once!");
|
|
// Allow multiple files for a function
|
|
with (indexFunctionArray[m[1]]) {
|
|
filename = filename + "|" + fname;
|
|
// print("filename = " + filename);
|
|
}
|
|
}
|
|
else {
|
|
indexFunctionArray[m[1]] = {filename:fname};
|
|
}
|
|
//reset comment
|
|
comment = "";
|
|
}
|
|
|
|
|
|
firstLine = false;
|
|
}
|
|
|
|
// Write table of contents.
|
|
for (var i=0; i < functionDocArray.length; i++) {
|
|
with (functionDocArray[i]) {
|
|
out.writeLine('function <A HREF=#' + name +
|
|
'>' + name + '</A><BR>');
|
|
}
|
|
}
|
|
out.writeLine('<HR>');
|
|
|
|
// Now write the saved function documentation.
|
|
for (i=0; i < functionDocArray.length; i++) {
|
|
with (functionDocArray[i]) {
|
|
out.writeLine('<A NAME=' + name + '>');
|
|
out.writeLine(text);
|
|
}
|
|
}
|
|
out.writeLine('</BODY></HTML>');
|
|
|
|
// Now clean up the doc array
|
|
functionDocArray = [];
|
|
}
|
|
|
|
/**
|
|
* Process function and associated comment.
|
|
* @param name the name of the function
|
|
* @param args the args of the function as a single string
|
|
* @param comment the text of the comment
|
|
* @return a string for the HTML text of the documentation
|
|
*/
|
|
function processFunction(name, args, comment) {
|
|
if (debug)
|
|
print("Processing " + name + " " + args + " " + comment);
|
|
return "<H2>Function " + name + "</H2>" +
|
|
"<PRE>" +
|
|
"function " + name + "(" + args + ")" +
|
|
"</PRE>" +
|
|
processComment(comment,0,name) +
|
|
"<P><BR><BR>";
|
|
}
|
|
|
|
/**
|
|
* Process a method being bound to a prototype.
|
|
* @param proto the name of the prototype
|
|
* @param name the name of the function
|
|
* @param args the args of the function as a single string
|
|
* @param comment the text of the comment
|
|
* @return a string for the HTML text of the documentation
|
|
*/
|
|
function processPrototypeMethod(proto, name, args, comment) {
|
|
if (debug)
|
|
print("Processing " + proto + ".prototype." + name + " " + args + " " + comment);
|
|
return "<H2> Method " + proto + ".prototype." + name + "</H2>" +
|
|
"<PRE>" +
|
|
proto + ".prototype." + name + " = function(" + args + ")" +
|
|
"</PRE>" +
|
|
processComment(comment,0,name) +
|
|
"<P><BR><BR>";
|
|
}
|
|
|
|
|
|
/**
|
|
* Process comment.
|
|
* @param comment the text of the comment
|
|
* @param firstLine shows if comment is at the beginning of the file
|
|
* @param fname name of the file (without path)
|
|
* @return a string for the HTML text of the documentation
|
|
*/
|
|
function processComment(comment,firstLine,fname) {
|
|
var tags = {};
|
|
// Use the "lambda" form of regular expression replace,
|
|
// where the replacement object is a function rather
|
|
// than a string. The function is called with the
|
|
// matched text and any parenthetical matches as
|
|
// arguments, and the result of the function used as the
|
|
// replacement text.
|
|
// Here we use the function to build up the "tags" object,
|
|
// which has a property for each "@" tag that is the name
|
|
// of the tag, and whose value is an array of the
|
|
// text following that tag.
|
|
comment = comment.replace(/@(\w+)\s+([^@]*)/g,
|
|
function (s, name, text) {
|
|
var a = tags[name] || [];
|
|
a.push(text);
|
|
tags[name] = a;
|
|
return "";
|
|
});
|
|
|
|
// if we have a comment at the beginning of a file
|
|
// store the comment for the index file
|
|
if (firstLine) {
|
|
indexFileArray[fname] = comment;
|
|
}
|
|
|
|
var out = comment + '<P>';
|
|
if (tags["param"]) {
|
|
// Create a table of parameters and their descriptions.
|
|
var array = tags["param"];
|
|
var params = "";
|
|
for (var i=0; i < array.length; i++) {
|
|
var m = array[i].match(/(\w+)\s+(.*)/);
|
|
params += '<TR><TD><I>'+m[1]+'</I></TD>' +
|
|
'<TD>'+m[2]+'</TD></TR>';
|
|
}
|
|
out += '<TABLE WIDTH="90%" BORDER=1>';
|
|
out += '<TR BGCOLOR=0xdddddddd>';
|
|
out += '<TD><B>Parameter</B></TD>';
|
|
out += '<TD><B>Description</B></TD></TR>';
|
|
out += params;
|
|
out += '</TABLE><P>';
|
|
}
|
|
if (tags["return"]) {
|
|
out += "<DT><B>Returns:</B><DD>";
|
|
out += tags["return"][0] + "</DL><P>";
|
|
}
|
|
if (tags["author"]) {
|
|
// List the authors together, separated by commas.
|
|
out += '<DT><B>Author:</B><DD>';
|
|
var array = tags["author"];
|
|
for (var i=0; i < array.length; i++) {
|
|
out += array[i];
|
|
if (i+1 < array.length)
|
|
out += ", ";
|
|
}
|
|
out += '</DL><P>';
|
|
}
|
|
if (tags["version"]) {
|
|
// Show the version.
|
|
out += '<DT><B>Version:</B><DD>';
|
|
var array = tags["version"];
|
|
for (var i=0; i < array.length; i++) {
|
|
out += array[i];
|
|
if (i+1 < array.length)
|
|
out += "<BR><DD>";
|
|
}
|
|
out += '</DL><P>';
|
|
}
|
|
if (tags["see"]) {
|
|
// List the see modules together, separated by <BR>.
|
|
out += '<DT><B>Dependencies:</B><DD>';
|
|
var array = tags["see"];
|
|
for (var i=0; i < array.length; i++) {
|
|
out += array[i];
|
|
if (i+1 < array.length)
|
|
out += "<BR><DD>";
|
|
}
|
|
out += '</DL><P>';
|
|
}
|
|
if (tags["lastmodified"]) {
|
|
// Shows a last modified description with client-side js.
|
|
out += '<DT><B>Last modified:</B><DD>';
|
|
out += '<script><!--\n';
|
|
out += 'document.writeln(document.lastModified);\n';
|
|
out += '// ---></script>\n';
|
|
out += '</DL><P>';
|
|
}
|
|
|
|
// additional tags can be added here (i.e., "if (tags["see"])...")
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Create an html output file
|
|
* @param outputdir directory to put the file
|
|
* @param htmlfile name of the file
|
|
*/
|
|
function CreateOutputFile(outputdir,htmlfile)
|
|
{
|
|
if (outputdir==null)
|
|
{
|
|
var outname = htmlfile;
|
|
}
|
|
else
|
|
{
|
|
var separator = Packages.java.io.File.separator;
|
|
var outname = outputdir + separator + htmlfile.substring(htmlfile.lastIndexOf(separator),htmlfile.length);
|
|
}
|
|
print("output file: " + outname);
|
|
return new File(outname);
|
|
}
|
|
|
|
/**
|
|
* Process a javascript file. Puts the generated HTML file in the outdir
|
|
* @param filename name of the javascript file
|
|
* @inputdir input directory of the file (default null)
|
|
*/
|
|
function processJSFile(filename,inputdir)
|
|
{
|
|
if (debug) print("filename = " + filename + " inputdir = " + inputdir);
|
|
|
|
if (!filename.match(/\.js$/)) {
|
|
print("Expected filename to end in '.js'; had instead " +
|
|
filename + ". I don't treat the file.");
|
|
} else {
|
|
if (inputdir==null)
|
|
{
|
|
var inname = filename;
|
|
}
|
|
else
|
|
{
|
|
var separator = Packages.java.io.File.separator;
|
|
var inname = inputdir + separator + filename;
|
|
}
|
|
print("Processing file " + inname);
|
|
|
|
var f = new File(inname);
|
|
|
|
// create the output file
|
|
var htmlfile = filename.replace(/\.js$/, ".html");
|
|
|
|
var out = CreateOutputFile(outputdir,htmlfile);
|
|
|
|
processFile(f, filename, inputdir, out);
|
|
out.close();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate index files containing links to the processed javascript files
|
|
* and the generated functions
|
|
*/
|
|
function GenerateIndex(dirname)
|
|
{
|
|
// construct the files index file
|
|
var out = CreateOutputFile(outputdir,indexFile);
|
|
|
|
// write the beginning of the file
|
|
out.writeLine('<HTML><HEADER><TITLE>File Index - directory: ' + dirname + '</TITLE><BODY>');
|
|
out.writeLine('<H1>File Index - directory: ' + dirname + '</H1>\n');
|
|
out.writeLine('<TABLE WIDTH="90%" BORDER=1>');
|
|
out.writeLine('<TR BGCOLOR=0xdddddddd>');
|
|
out.writeLine('<TD><B>File</B></TD>');
|
|
out.writeLine('<TD><B>Description</B></TD></TR>');
|
|
|
|
var separator = Packages.java.io.File.separator;
|
|
|
|
// sort the index file array
|
|
var SortedFileArray = [];
|
|
for (var fname in indexFileArray)
|
|
SortedFileArray.push(fname);
|
|
SortedFileArray.sort();
|
|
|
|
for (var i=0; i < SortedFileArray.length; i++) {
|
|
var fname = SortedFileArray[i];
|
|
var htmlfile = fname.replace(/\.js$/, ".html");
|
|
out.writeLine('<TR><TD><A HREF=\"' + htmlfile + '\">' + fname + '</A></TD></TD><TD>');
|
|
if (indexFileArray[fname])
|
|
out.writeLine(indexFileArray[fname]);
|
|
else
|
|
out.writeLine('No comments');
|
|
out.writeLine('</TD></TR>\n');
|
|
}
|
|
out.writeLine('</TABLE></BODY></HTML>');
|
|
out.close();
|
|
|
|
// construct the functions index file
|
|
var out = CreateOutputFile(outputdir,indexFunction);
|
|
|
|
// write the beginning of the file
|
|
out.writeLine('<HTML><HEADER><TITLE>Function Index - directory: ' + dirname + '</TITLE><BODY>');
|
|
out.writeLine('<H1>Function Index - directory: ' + dirname + '</H1>\n');
|
|
out.writeLine('<TABLE WIDTH="90%" BORDER=1>');
|
|
out.writeLine('<TR BGCOLOR=0xdddddddd>');
|
|
out.writeLine('<TD><B>Function</B></TD>');
|
|
out.writeLine('<TD><B>Files</B></TD></TR>');
|
|
|
|
// sort the function array
|
|
var SortedFunctionArray = [];
|
|
for (var functionname in indexFunctionArray)
|
|
SortedFunctionArray.push(functionname);
|
|
SortedFunctionArray.sort();
|
|
|
|
for (var j=0; j < SortedFunctionArray.length; j++) {
|
|
var funcname = SortedFunctionArray[j];
|
|
with (indexFunctionArray[funcname]) {
|
|
var outstr = '<TR><TD>' + funcname + '</TD><TD>';
|
|
var filelst = filename.split("|");
|
|
for (var i in filelst) {
|
|
var htmlfile = filelst[i].replace(/\.js$/, ".html");
|
|
outstr += '<A HREF=\"' + htmlfile + '#' + funcname + '\">' + filelst[i] + '</A> ';
|
|
}
|
|
outstr += '</TD></TR>';
|
|
out.writeLine(outstr);
|
|
}
|
|
}
|
|
out.writeLine('</TABLE></BODY></HTML>');
|
|
out.close();
|
|
}
|
|
|
|
|
|
/**
|
|
* prints the options for JSDoc
|
|
*/
|
|
function PrintOptions()
|
|
{
|
|
print("You can use the following options:\n");
|
|
print("-d: specify an output directory for the generated html files\n");
|
|
print("-i: processes all files in an input directory (you can specify several directories)\n");
|
|
quit();
|
|
}
|
|
|
|
|
|
// Main Script
|
|
// first read the arguments
|
|
if (! arguments)
|
|
PrintOptions();
|
|
|
|
for (var i=0; i < arguments.length; i++) {
|
|
if (debug) print("argument: + \'" + arguments[i] + "\'");
|
|
if (arguments[i].match(/^\-/)) {
|
|
if (String(arguments[i])=="-d"){
|
|
// output directory for the generated html files
|
|
|
|
outputdir = String(arguments[i+1]);
|
|
if (debug) print("outputdir: + \'" + outputdir + "\'");
|
|
|
|
i++;
|
|
}
|
|
else if (String(arguments[i])=="-i"){
|
|
// process all files in an input directory
|
|
|
|
DirList.push(String(arguments[i+1]));
|
|
if (debug) print("inputdir: + \'" + arguments[i+1] + "\'");
|
|
i++;
|
|
}
|
|
else {
|
|
print("Unknown option: " + arguments[i] + "\n");
|
|
PrintOptions();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we have a single file
|
|
if (debug) print("file: + \'" + arguments[i] + "\'");
|
|
|
|
FileList.push(String(arguments[i]));
|
|
}
|
|
}
|
|
|
|
// first handle the single files
|
|
for (var i in FileList)
|
|
processJSFile(FileList[i],null);
|
|
|
|
// then handle the input directories
|
|
for (var j in DirList) {
|
|
var inputdir = String(DirList[j]);
|
|
|
|
print("Process input directory: " + inputdir);
|
|
|
|
// clean up index arrays
|
|
var indexFileArray = [];
|
|
var indexFunctionArray = [];
|
|
|
|
// for the directory name get rid of ../../ or ..\..\
|
|
inputDirName = inputdir.replace(/\.\.\/|\.\.\\/g,"");
|
|
|
|
indexFile = indexFileName + "_" + inputDirName + ".html";
|
|
indexFunction = indexFunctionName + "_" + inputDirName + ".html";
|
|
|
|
print("indexFile = " + indexFile);
|
|
print("indexFunction = " + indexFunction);
|
|
|
|
// read the files in the directory
|
|
var DirFile = new java.io.File(inputdir);
|
|
var lst = DirFile.list();
|
|
var separator = Packages.java.io.File.separator;
|
|
|
|
for (var i=0; i < lst.length; i++)
|
|
{
|
|
processJSFile(String(lst[i]),inputdir);
|
|
}
|
|
|
|
// generate the index files for the input directory
|
|
GenerateIndex(inputDirName);
|
|
}
|
|
|
|
|
|
|