3

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?

Christopher
  • 1,723
  • 1
  • 18
  • 31
  • 2
    I know this is not what you are looking for, but have you tried ReSharper 6? It has a very nice JavaScript intellisense support without the need of vsdoc. Maybe it would be easier to just buy a license for a new developer then to have to not only maintain source code but also vsdocs? – Ilya Volodin Mar 10 '12 at 16:46
  • 1
    @Ilya Volodin, ReSharper is fantastic. The augmentation of JavaScript Intellisense that it provides is wonderful; however, it's really only doing what VisualStudio attempts to do in a virtual, standards-compliant browser. In order for VS to provide JS Intellisense at all, it must faux execute the code using a JS engine (usually IE's). ReSharper _does_ improve upon this greatly; but this isn't the issue. Again, to jQuery, with and without RS, I can get chained Intellisense on $('#node').children().children()--this has to be related to their vsdoc (afaik), but I'm still missing something. – Christopher Mar 15 '12 at 03:20

1 Answers1

1

I agree with @Ilya Volodin. ReSharper is a great tool for visual studio. I use it for only a month and I can not do without.

This does not answer your question but it would be very useful to you.

Here is a good summary that can be found on the official website:

"ReSharper is a renowned productivité Tool That Makes Microsoft Visual Studio IDE is much better. Thousands of. NET developers worldwide wonder how they 've ever Lived without ReSharper's code inspections, automated refactorings, blazing fast shipping, and coding assistance."

FBruynbroeck
  • 499
  • 3
  • 15
  • 1
    As I commented to @Ilya Volodin, ReSharper _is_ awesome; however, it doesn't in-and-of itself solve the problem. – Christopher Mar 15 '12 at 03:22
  • We us Resharper 7 at the moment and it does not include intellisense for namespaced script files. If you have a file `Address.js` namespaced as `AppName.Customer.Address` and it has a method `ValidateCustomerAddress()` which for example calls `StringHasNoNumbers()` in another namespaced file, named `Util.js` namespaced as `AppName.Common.Util` then intellisense is not going to find `AppName.Common.Util.StringHasNoNumbers()` as it doesn't exist in the scope of the `AppName.Customer.Address` namespace. Add the `///reference...` and Resharper is able to give you intellisense on namespaced files. – Nope Jan 15 '13 at 13:40
  • 1
    FYI Resharper slowed my Visual Studio instance to a crawl, wasn't worth it. – Chris Moschini Feb 23 '13 at 11:05