Saturday, February 28, 2009

Automatic JavaScript Documenting

The main idea is to help in creating documents like this:
It is possible to automatically document JavaScript by several ways:
  • by JavaScript itself
  • by external JavaScript parser
To automatically document JavaScript by JavaScript itself next approach could be used:
<head>
<script type="text/javascript" src="js/prototype-1.6.0.3.js"></script>

<script type="text/javascript">
// document2str
// document object to string
// params:
// name - object name
// returns
// object documentation as string
function document2str(name) {
var inner = function(obj, tab, res){
for(var i in obj) {
if (typeof(obj[i])=='function') {
var s = obj[i].toString();
var l = s.indexOf('(');
res += tab+i + ' ' + 'function' + s.substr(l, s.indexOf(')')-l+1) + "\n";
} else {
res += tab+i + ' ' + typeof(obj[i]) + "\n";
if (typeof(obj[i])=='object')
res = inner(obj[i], tab+' ', res);
}
}
return res;
}
return inner(eval(name), '', name+"\n");
}

// document2obj
// document object as object
// params:
// name - object name
// returns
// object documentation as object
function document2obj(str) {
var inner = function(obj, res){
for(var i in obj) {
if (typeof(obj[i])=='function') {
var s = obj[i].toString();
var l = s.indexOf('(');
res[i] = 'function' + s.substr(l, s.indexOf(')')-l+1);
} else {
res[i] = typeof(obj[i]);
if (typeof(obj[i])=='object')
res[i] = inner(obj[i], {});
}
}
return res;
}
return inner(eval(str), {});
}
</script>
</head>

<body>
<pre id="pre1">
</pre>

<pre id="pre2">
</pre>

<script type="text/javascript">
$('pre1').innerHTML = document2str('Form');

var obj = document2obj('Form');
$('pre2').innerHTML = Object.toJSON(obj);
</script>
</body>

document2str output:
Form
reset function(form)
serializeElements function(elements, options)
Methods object
serialize function(form, options)
getElements function(form)
getInputs function(form, typeName, name)
disable function(form)
enable function(form)
findFirstElement function(form)
focusFirstElement function(form)
request function(form, options)
Element object
focus function(element)
select function(element)
Methods object
serialize function(element)
getValue function(element)
setValue function(element, value)
clear function(element)
present function(element)
activate function(element)
disable function(element)
enable function(element)
Serializers object
input function(element, value)
inputSelector function(element, value)
textarea function(element, value)
select function(element, value)
selectOne function(element)
selectMany function(element)
optionValue function(opt)
Observer function()
EventObserver function()
serialize function(element)
getValue function(element)
setValue function(element, value)
clear function(element)
present function(element)
activate function(element)
disable function(element)
enable function(element)
Observer function()
EventObserver function()
serialize function(form, options)
getElements function(form)
getInputs function(form, typeName, name)
disable function(form)
enable function(form)
findFirstElement function(form)
focusFirstElement function(form)
request function(form, options)

document2obj output:
{"reset": "function(form)", "serializeElements": "function(elements, options)", "Methods": {"serialize": "function(form, options)", "getElements": "function(form)", "getInputs": "function(form, typeName, name)", "disable": "function(form)", "enable": "function(form)", "findFirstElement": "function(form)", "focusFirstElement": "function(form)", "request": "function(form, options)"}, "Element": {"focus": "function(element)", "select": "function(element)", "Methods": {"serialize": "function(element)", "getValue": "function(element)", "setValue": "function(element, value)", "clear": "function(element)", "present": "function(element)", "activate": "function(element)", "disable": "function(element)", "enable": "function(element)"}, "Serializers": {"input": "function(element, value)", "inputSelector": "function(element, value)", "textarea": "function(element, value)", "select": "function(element, value)", "selectOne": "function(element)", "selectMany": "function(element)", "optionValue": "function(opt)"}, "Observer": "function()", "EventObserver": "function()", "serialize": "function(element)", "getValue": "function(element)", "setValue": "function(element, value)", "clear": "function(element)", "present": "function(element)", "activate": "function(element)", "disable": "function(element)", "enable": "function(element)"}, "Observer": "function()", "EventObserver": "function()", "serialize": "function(form, options)", "getElements": "function(form)", "getInputs": "function(form, typeName, name)", "disable": "function(form)", "enable": "function(form)", "findFirstElement": "function(form)", "focusFirstElement": "function(form)", "request": "function(form, options)"}

Using of JavaScript itself has some limitations.
It hides object creation details, like initialize in Prototype.

To automatically document JavaScript by external JavaScript parser Rhino project could be used.

function compileImpl of a class org.mozilla.javascript.Context contains call of JavaScript parser:
ScriptOrFnNode tree;
if (sourceString != null) {
tree = p.parse(sourceString, sourceName, lineno);
} else {
tree = p.parse(sourceReader, sourceName, lineno);
}

After parsing tree contains list of symbols and functions that are available through:
public final FunctionNode getFunctionNode(int i)
public Map<String,Symbol> getSymbolTable()

Also parsed tree of tokens could be traversed by using:
public boolean hasChildren() {
return first != null;
}

public Node getFirstChild() {
return first;
}

public Node getLastChild() {
return last;
}

public Node getNext() {
return next;
}

No comments: