I'm in the process of refactoring my JavaScript library to utilize a single namespace. We have ~200 modules, which previously registered themselves as jQuery plugins or on the global object (bad). In the past dispensation, to get Intellisense working, I added module references for each module (from which I wanted Intellisense) as a
/// <reference path="" />
to the top of every module file.
Everything about the previous dispensation was flawed, fragile and inelegant.
I hope to fix that in the new dispensation. One of the primary goals of this refactoring is to make it easy for new developers to get started working in the library, and Intellisense is of great benefit.
Currently, I'm concatenating all of the *.js files into a single nameSpace-vsdoc.js file. Every method of every class is documented using vsdoc syntax. Every module uses that, single vsdoc reference. This works OK, but it's clumsy. Intellisense works 300% better than before, but it's still not accurate enough. It misses lots of my xml documentation and it doesn't recurse well into methods/classes which return even slightly complicated objects.
YUI Doc offers a way to build documentation from the JsDoc syntax, but that doesn't help with Intellisense. A deep soul-googling has failed to reveal any 3rd party solutions.
Are there any tools to generate VsDocs in a more Intellisense-intelligent way?
UPDATE:
After some extensive thought, testing and incremental refactorings, I have a basic namespace that looks like this jsFiddle.
This enables me to write loosely couple modules in self-executing functions, which register the desired methods on the namespace. All of the modules begin with:
/// <reference path="~/js/NameSpace-vsdoc.js" />
I generate this vsdoc with a simple Perl script, which I've attached to a VS 2010 build event:
use strict;
my $dir = $ARGV[0];
my $destfile = "$dir\\js\\NameSpace-vsdoc.js";
unlink($destfile);
my $js = "";
$js .= extractFile("$dir\\js\\_first-vsdoc.js");
$js .= extractFile("$dir\\js\\NameSpace.js");
$js .= extract("$dir\\js\\modules");
#Add additional directories as needed
$js .= extractFile("$dir\\js\\_last-vsdoc.js");
open(VSDOC, "> $destfile") or die("Cannot open vsdoc file: $destfile ; $!");
print VSDOC $js;
close(VSDOC);
sub extract
{
my $ret = "";
my $path = $_[0];
opendir(JSDIR, $path) or die("Cannot open js directory: $path ; $!");
while((my $filename = readdir(JSDIR)))
{
if($filename =~ /.*\.js$/ &&
$filename !~ /-vsdoc/ &&
$filename !~ /_first/ &&
$filename !~ /_last/ &&
$filename !~ /.min\.js/)
{
$ret .= extractFile("$path\\$filename");
}
}
closedir(JSDIR);
return $ret;
}
sub extractFile
{
my $ret = "";
my $filename = $_[0];
open(JSFILE, "$filename") or die("Cannot open js file: $filename ; $!");
while((my $line = <JSFILE>))
{
if($line !~ m/-vsdoc\.js/ )
{
$ret .= $line;
}
}
close(JSFILE);
return $ret;
}
printf("Finished generating NameSpace vsdoc.\n");
The _first-vsdoc.js and _last-vsdoc.js files wrap the entire contents in a self-executing function. I then pass the resulting vsdoc to Closure Compiler, YUI Compressor and Uglify as needed/appropriate.
This process works much better than before, but it is still not without its flaws.
Starting from scratch, in NewModule.js which references NameSpace-vsdoc.js, I get proper Intellisense:
Ns.register() //visible
Ns.controls.register() //visible
Ns.actions.register() //visible
However, when I define NewModule.js as (and compile):
(function _alertClosure() {
Ns.register('alert', function alert(someText) {
///insert proper vsdoc style comment
});
}());
I do not get proper Intellisense for:
Ns.alert() //no Intellisense help
which is perplexing, because it works so well on sub-namespaces. I'm forced to do this:
Ns.alert = Ns.alert || Ns.register('alert', function ....
Compile, and suddenly (obviously) Intellisense works as expected.
Intellisense works with chained methods using jQuery's vsdoc (which I have studied closely in constructing this process) and jQuery doesn't resort to the y.x = y.x || new x()
trickery to make it happen.
So here is the revised question: From a structural standpoint, the only discernible difference I can perceive between jQuery's vsdoc and my own is that jQuery assembles the entire namespace inside the same closure. My namespace and each of my modules are wrapped in individual closures. In comparison, my vsdoc looks like a long string of self-executing functions.
There is simply too much risk associated with forgoing the closure/module pattern; and it's difficult to test the hypothesis in isolation. Intellisense works well when the library is small and therefore unable to generate thousands of "Javascript Intellisense Message: C:\\js\NameSpace-vsdoc.js(40:16) : Object required" errors.
Ideas?