Tales from the Evil Empire

Bertrand Le Roy's blog

The format for JavaScript doc comments

Xml documentation annotations are going to drive JavaScript IntelliSense in Visual Studio Orcas (the next version of Visual Studio). For more than a year now, we've been including xml doc comments to all public APIs in the Microsoft Ajax Library (which are a great place to check out some examples of those comments). We also use the doc comments to automatically generate parameter validation code in the debug version of our scripts.

The format we've been using is an extension of the format that C# and VB.NET are using so it should look familiar to .NET developers. The main differences are the additional attributes we added to convey the (optional) type information that is not provided by the language itself and the place where those comments are written.

Doc comment position

In C# or VB.NET, the doc comment are written before what they describe:

/// <summary>
/// Summary description for Class1
/// </summary>
public class Class1

In JavaScript, we decided to put that information *inside* what it describes so that it can be available at runtime: JavaScript has the interesting feature that calling toString on a function returns the code of this function (when it's propertly implemented), including the comments and thus the doc comments. Here's a similar example in JavaScript where the documentation is written inside of a class constructor:

MyNamespace.Class1 = function() {
    /// <summary>
    /// Summary description for Class1
    /// </summary>

Another difference with C# or VB.NET is that property and event accessors are two different entities in JavaScript. For this reason, we had to choose where the documentation should be for those members. Properties should be documented in the getter and events in the "adder" for this reason:

get_myProperty: function() {
    /// <value>Documentation goes on the getter.</value>
    return this._myProperty;
},
set_myProperty: function(value) {
    // No doc comments here
    this._myProperty = value;
}

Doc comment tags

The locid attribute

Most of the tags that I'm about to describe can have their description text inside of the tag itself or the tag can reference an external description using an identifier as the value of the locid attribute. This of course enables documentation to be localized.

The choice of the identifier is free but our team is using the following convention (the identifiers are actually being automatically generated by our preprocessor):

  • “T:J#MyNameSpace.MyType” for types
  • “M:J#MyNameSpace.MyType.myMethod” for methods (use #ctor as the method name for the constructor)
  • “P:J#MyNameSpace.MyType.myProperty” for properties (in this case the getter would be get_myProperty)
  • “F:J#MyNameSpace.MyType.myField” for fields
  • “E:J#MyNameSpace.MyType.myEvent” for events (in this case the adder would be add_myEvent)
Type attributes

The param, returns, value and field tags that are described below all share the same description of types using attributes. All type information is always optional but you should note that not specifying the type is not the same as specifying type="Object" as everything is not an instance of Object in JavaScript.

The type attribute is used to specify the name of the type of the parameter, return value, property or field.

There are a few cases though where that type is not enough. Namely, in JavaScript, there is no integer type, only a generic Number type. For that reason, and because it's often useful to make that distinction, you can explicitly specify that something is an integer by using both Number as the type and setting the integer attribute to true:

/// <field name="index" type="Number" integer="true"/>

Similarly, DOM elements don't have a type that's well-defined across all browsers. You can specify that somthing is a DOM element by setting the domElement attribute to true. No type should be specified in this case.

Recent research shows that non-null types are extremely useful and should probably represent the norm rather than the exception. For that reason, we added the mayBeNull attribute and made its default value false.

Finally, if the type is Array, it may be desirable to specify the type of the elements of the array (JavaScript has only one variant array type, there is no int[] or String[]). The elementType, elementInteger, elementDomElement and elementMayBeNull are the equivalents for the array elements of the type, integer, domElement and mayBeNull attributes.

<summary locid="descriptionID">Description</summary>

The summary tag can be used in a constructor to describe its class, interface or enumeration, or inside a method, property getter or event "adder" to describe respectively the method, property or event.

<param name="parameterName"
    mayBeNull="true|false" optional="true|false"
    type="ParameterType" parameterArray="true|false"
    integer="true|false" domElement="true|false"
    elementType="ArrayElementType" elementInteger="true|false"
    elementDomElement="true|false"
    elementMayBeNull="true|false">Description</param>

The param tag is used to describe the parameters of a method or constructor. The param tags should be in the same order as the method or constructor's parameters and have the same names.

Optional parameters (which are a way to work around the inexistence of overloads in JavaScript) can be specified using the optional attribute. Optional parameters should come last in the list of parameters and it's good practice to put the "most optional" parameters last.

The parameterArray attribute can be used on the last parameter to specify that this parameter may be repeated as many times as the caller desires. A typical example of this is String.format, which can take as many arguments as the format string enables.

<returns
    type="ValueType" integer="true|false" domElement="true|false"
    mayBeNull="true|false" elementType="ArrayElementType"
    elementInteger="true|false" elementDomElement="true|false"
    elementMayBeNull="true|false">Description</returns>

The returns tag is used to describe the return value of a method. It should be used only if the function returns a value (in other words if it contains a return statement that is not just "return;").

<value
    type="ValueType" integer="true|false" domElement="true|false"
    mayBeNull="true|false" elementType="ArrayElementType"
    elementInteger="true|false" elementDomElement="true|false"
    elementMayBeNull="true|false"
    locid="descriptionID">Description</value>

The value tag describes a property (which shouldn't have a summary tag).

<field name="fieldName" type="FieldType"
    integer="true|false" domElement="true|false" mayBeNull="true|false"
    elementType="ArrayElementType" elementInteger="true|false"
    elementDomElement="true|false" elementMayBeNull="true|false"
    locid="descriptionID">Description</field>

The field tag (which doesn't exist in C# and VB.NET because in those languages the summary tag can be used) is used inside of a class, interface or enumeration constructor to describe a field. A field can't be described near the field itself in JavaScript because the field itself doesn't have a body to contain that description.

<reference path="path/to/the/script/reference.js"
    assembly="Assembly.Name" name="ScriptResourceName.js"/>

The reference tag is used by Visual Studio to describe a dependency a script has with another script file. This enables the IDE to provide IntelliSense on the namespaces and types that are defined in this other file. This tag should be at the top of the file, outside of any code.

The description

The contents of the description itself, whether the tag is summary, param, returns, field or value, is described by the exact same convention that works for C# and VB.NET doc comments. It can be plain text or text containing other XML tags, as described here:

http://msdn2.microsoft.com/en-us/library/5ast78ax(VS.80).aspx

What's next?

This is the convention we're using to document and enhance our scripts and we encourage you to do the same, whether you use Microsoft Ajax or not if only to give your users IntelliSense in Visual Studio.

Similarly, there is no reason why Visual Studio should be the only IDE to handle XML doc comments. We would love it if other IDEs chose to use that format to provide better IntelliSense (or auto-completion).

In a future post, I'll describe how you can extract those XML documentation comments to build usable documentation using existing tools that were designed for managed code.

UPDATE: added the optional attribute for params, which I had omitted.

UPDATE 2: Omar Khan gave a great talk at Mix 07 on the new features in Visual Studio Orcas. Around minute 45, he starts demonstrating JavaScript IntelliSense:
http://sessions.visitmix.com/default.asp?event=1011&session=2012&pid=DEV14&disc=&id=1523&year=2007&search=DEV14

UPDATE 3: added "J#" to naming convention for the locids, to enable managed code and script to implement the same namespaces without a collision in the locids. Also removed locid from param and returns.

UPDATE 4: ScriptDoc, the documentation extraction tool that builds xml files from these doc comments for consumption by Sandcastle, is now available on Codeplex.

Comments

Wallym said:

Awesome, thanks Bertrand.

# April 23, 2007 10:25 PM

Anand Raman said:

# April 24, 2007 12:59 AM

Fabio Serra said:

Why don't use jsdoc?

(http://jsdoc.sourceforge.net/)

It is more compact and it is used by a lot of Javascript library like Yhaoo UI (http://developer.yahoo.com/yui/) or in the Firefox javascript source code.

Today, the most popular Javascript IDE as JSEclipse and Aptana provide intellisense using jsdoc and the inline comments syntax.

# April 25, 2007 1:20 PM

Bertrand Le Roy said:

Fabio: for several reasons. First, JSDoc comments are not accessible at runtime. Second, they're missing many features that we need. And most of all, xml doc comments exist in .NET since its inception. .NET developers are very much used to them and how they work. There are also many, many tools that already work with xml doc comments (more about this in future posts) and that will work unmodified with this convention.

# April 25, 2007 1:31 PM

Jeffrey Becker said:

may I suggest a paramSet / overload tag for methods?  I've often written functions (especially constructors) in js which do /very/ different things depending on not only the number but type and order of parameters which are passed into a function.  In these cases it's even MORE important to have good documentation because they're often implemented by looking at the arguments array rather than arguments declared in the function definition.  A Fabio Serra mentioned jsdoc, which I dont feel really gets the job done mostly because I cant readily declare how I've overloaded my functions.

# May 7, 2007 9:06 PM

Bertrand Le Roy said:

Jeffrey: that's an interesting suggestion that I'll relay over to the Visual Studio team for a future version. It's not a pattern we're pushing because just looking at the parameters collection is an expensive operation. We prefer to encourage optional parameters because they perform better and are a lot easier to implement. But I can see why people do overloads in JavaScript and I'll definitely relay the suggestion.

# May 7, 2007 9:17 PM

Speednet said:

In VB.NET and C# I commonly use the <remarks /> comment tag to document some other development notes about the method/property that do not fit into the <summary /> or other tags, and which I would consider to be "sub-comments".

So, I have two requests:

1. Can you please formally add support for the <remarks /> comment tag in JS?

2. I wish there was a small "more" link at the bottom of intellisense prompts, which would give the developer real-time access to the <remarks /> info.

Thanks,

Todd

# May 11, 2007 11:00 AM

Bertrand Le Roy said:

Speednet: not for the moment but I'll keep that in mind. If you include those tags today, the worst that can happen is that they will get ignored by the tools. Thanks for the suggestion.

# May 11, 2007 2:35 PM

ScottGu's Blog said:

One of the features that web developers will really like with VS 2008 is its built-in support for JavaScript

# June 22, 2007 1:57 AM

BusinessRx Reading List said:

One of the features that web developers will really like with VS 2008 is its built-in support for JavaScript

# June 22, 2007 2:08 AM

ASP.NET said:

One of the features that web developers will really like with VS 2008 is its built-in support for JavaScript

# June 22, 2007 2:24 AM

Intellisense en JavaScript con VS 2008 « Thinking in .NET said:

Pingback from  Intellisense en JavaScript con VS 2008 &laquo; Thinking in .NET

# June 22, 2007 1:16 PM

Soven Shrivastav said:

VS 2008 JavaScript Intellisense

# June 23, 2007 12:16 AM

一个小泡 said:

VS 2008 JavaScript Intellisense

# June 24, 2007 8:05 PM

Atlas and more said:

ScriptDoc is a tool that extracts documentation from JavaScript files and packages it into XML files

# June 27, 2007 7:30 PM

Caterwomtious said:

Hi Bertrand

Like some others, my first thought was "this sounds great, but why not jsDoc?" You make a good argument for using XML instead, but it would still be useful to add jsDoc support even if it is for a subset of the functionality.

Why? Because there's a huge body of JsDoc-documented code out there that VS.net could interpret straight away, without needing to run any conversion tools. That's a big win.

# June 29, 2007 4:28 PM

Bertrand Le Roy said:

Caterwomtious: I agree, and I've passed this suggestion along to the right team for a future version (a while ago :) ).

# June 29, 2007 4:50 PM

cnblogs.com said:

作者: Truly 日期:2007.8.5 首先我们要遵循JavaScript注释规范,详见 ScriptDoc 和 weblogs.asp.net/.../2007

# August 8, 2007 4:56 AM

Truly said:

I modified sandcastle, then I generate a CHM for MicrosoftAjax.js, and I still working on it.

you can see the shots of the CHM from here:

www.cnblogs.com/.../849856.html

# August 9, 2007 11:15 AM

OpenSource Connections » Blog Archive » Javascript Intellisense, Documentation, & Visual Studio 2008 (Orcas) said:

Pingback from  OpenSource Connections  &raquo; Blog Archive   &raquo; Javascript Intellisense, Documentation, &#038; Visual Studio 2008 (Orcas)

# September 2, 2007 2:38 PM

Morten said:

Is there a way to document the parameters a handler function should take for events? I want to specify that for instance the first argument will be the sender object of some type, and the second will be the event argument that is an object with a couple of named fields.

Let's say this is how I fire my event:

 var handler = this.get_events().getHandler('valueChanged');

 if(handler) handler(this,{"oldValue":3,"newValue":7});

...it would be great if I could document what types the two arguments are, and what fields the second argument contains.

# September 5, 2007 1:14 PM

Bertrand Le Roy said:

Morten: Yes, I agree. Thanks for the suggestion.

# September 5, 2007 1:28 PM

Fine Art » The format for JavaScript doc comments - Tales from the Evil Empire said:

Pingback from  Fine Art &raquo; The format for JavaScript doc comments - Tales from the Evil Empire

# September 26, 2007 11:54 AM

Morten said:

I've created a set of webcontrols that registers scripts (both at runtime and designtime), and these scripts also reference other scripts using the <reference assembly.../> tags.

When I add the webcontrol to the page, I would think that the scripts also gets included in the page so I get intellisense on them, but apparently not.

I might be doing something wrong, but if not, I'd like to see this kind of support in Orcas too.

# October 1, 2007 3:55 PM

Bertrand Le Roy said:

Morten: you can get Intellisense on those files by including an explicit script reference to the page.

# October 1, 2007 3:57 PM

Your Websites, Our Passion! said:

It should be no surprise that JScript Documentation Comments power much of what you see in JScript IntelliSense

# November 6, 2007 2:35 PM

Noticias externas said:

It should be no surprise that JScript Documentation Comments power much of what you see in JScript IntelliSense

# November 6, 2007 3:00 PM

Ev said:

Is there a limit to the amount of js that can be commented?  I'm getting a strange error when the .js file with comments is over 256K.  I've tried splitting into two files and same result:

"Error updating JScript IntelliSense: JScript IntelliSense has been disabled for referenced scripts. A referenced script may have caused a stack overflow. Reopen this file to reenable IntelliSense."

# November 14, 2007 11:22 AM

Bertrand Le Roy said:

Ev: not that I know of, but send me mail through the contact form of this blog and I'll get you the right contacts to debug that issue.

# November 14, 2007 2:14 PM

Flying alone said:

The following items are covered XSLT JavaScript SQL CSS/XHTML Managed code (?) Tools &amp; resources

# November 30, 2007 3:27 AM

Jacky_xu said:

摘要

这周末不休息,差点忘了这件事……本期共有7篇文章: JavaScript文档注释的格式

VisualStudioOrcas中对JavaScript智能感知的支持

在ASP....

# December 3, 2007 11:51 PM

Jim Baltika said:

WebSite.WebCameraInfo.prototype = {

   ZoomLevel: 11,

....

Hi guys. Does any have any ideas how to comment prototype getter like this?

# December 15, 2007 1:03 PM

Bertrand Le Roy said:

Jim: that's not technically a getter, but you can document it from the constructor using a field tag.

# December 17, 2007 4:30 PM

lee576 said:

译给自己看

# January 17, 2008 10:18 PM

Erik said:

Is the Field tag still part of JS intellisense?  I can't find any documentation on it anywhere.

# January 28, 2008 8:26 PM

Bertrand Le Roy said:

It should be.

# January 29, 2008 1:27 PM

Brennan’s Blog » Blog Archive » Intellisense for jQuery in Visual Studio 2008 said:

Pingback from  Brennan&#8217;s Blog  &raquo; Blog Archive   &raquo; Intellisense for jQuery in Visual Studio 2008

# February 1, 2008 1:59 AM

Scott Hanselman's Computer Zen said:

# February 12, 2008 2:48 AM

ASPInsiders said:

Aptana has a cool Eclipse-based IDE for writing AJAX-y websites. It's got built-in support, via plugins,

# February 12, 2008 3:15 AM

Scott Hanselman's Computer Zen said:

# February 12, 2008 11:45 AM

JS IntelliSense with Namespaces in VS 2008 at Coderoni.com said:

Pingback from  JS IntelliSense with Namespaces in VS 2008 at Coderoni.com

# February 13, 2008 12:23 AM

Brennan’s Blog » Blog Archive » JavaScript Browser for Visual Studio 2008 said:

Pingback from  Brennan&#8217;s Blog  &raquo; Blog Archive   &raquo; JavaScript Browser for Visual Studio 2008

# February 18, 2008 12:53 PM

Brock Allen said:

In VS2008, if I use:

function Foo()

{

/// <param name='x' domElement='true'>x</param>

}

Should I get DOMElement intellisense for x? If so, it doesn't seem to be working. Same for:

/// <returns domElement='true'>

# February 25, 2008 2:17 PM

Bertrand Le Roy said:

@Brock: I don't think that's handled in 2008, no.

# February 25, 2008 2:27 PM

whatispunk said:

I'm also getting the same error as Ev.

"Error updating JScript IntelliSense: JScript IntelliSense has been disabled for referenced scripts. A referenced script may have caused a stack overflow. Reopen this file to reenable IntelliSense."

Any progress on that one? This is the only Google result for that error message.

# February 26, 2008 12:29 PM

Jeff King (msft) said:

@whatispunk: There actually is a limit to the XML Comment data per section.  This was a implementation limitation we could not work around.  I'm sorry to say that you'll just have to shorten your XML Comment data.  I'll keep this in mind to fix for our next release.  Thanks!

# February 27, 2008 1:42 AM

Mina said:

create comments by php

# April 14, 2008 11:51 AM

Chris Pietschmann said:

Do you have an example of how to Localize the JScript Intellisense Support using the locid? If so, could you please send me an example? You can contact me through the contact form on my blog. pietschsoft.com/contact.aspx

Thanks

# April 23, 2008 10:42 PM

VR2 said:

Could we have a static "parse" method added to all classes, in order for clients to be able to cast to type?

eg

Sys.SomeClass.parse = function(obj)

{///<returns type="Sys.SomeClass"/>

   return obj;

}

Client Code would be

function onSomeClassClick(sender, args)

{

   sender = Sys.SomeClass.parse(sender);

   args   = Sys.SomeClassEventArgs.parse(args);

   // Full JS intellisense now enabled.

}

Thanks

# May 12, 2008 9:31 AM

benizi said:

I think I'm missing something, but it might be related to Brock's question to which you replied, "@Brock: I don't think that's handled in 2008, no."

A simplified example:

/// <reference path="Stuff.js" />

var outside = new MyNamespace.Stuff();

outside.+++

Other.Thing.prototype = {

foo: function (inside) {

 /// <param name="inside" type="MyNamespace.Stuff">arg</param>

 inside.---

At the '+++', I get working Intellisense completion. At the '---', I don't. The point being that it obviously found the proper comments for the 'Stuff' class, since it works at one point in the file. Am I doing something wrong (specifying the class name improperly?)? or does VS2008 simply not do Intellisense for <param>'s?

Best,

Ben

# July 11, 2008 12:51 AM

Bertrand Le Roy said:

@Ben: There is a number of circumstances where IntelliSense doesn't quite work yet. The one you describe and a few others. This is greatly improved in SP1, and will get even better in the next Visual Studio.

# July 11, 2008 2:31 PM

VR2 said:

Again, Ben, an ability to statically parse or cast to type would solve that for you.

This ability can be added by us, retrospectively, via an extensions library applied after MS Ajax is downloaded.

eg

Sys.ApplicationLoadEventArgs.cast = function(obj)

{///<returns type="Sys.ApplicationLoadEventArgs"/>

   return obj;

}

By also doing this in your own classes, your constructor could have code like this:

inside = MyNamespace.Stuff.cast(inside);

inside.---; // Intellisense is now fully enabled.

Also, the lack of "in file" intellisense can be largely overcome by structuring your code differently to the way advertised/recommended.

Firstly you need to ensure that your namespace is defined in an external file (so the namespacing code can run and create the namespace for you ready to go). I have found adding a "_namespace.js" file to contain js intellisense references as well as namespace definition works well. This file is not required to be downloaded to the client. These can also be chained from child to parent folders, for each namespace required.

Secondly, after declaring your class (function) you can get intellisense by setting your function's prototype to that of the class you intend to inherit from. This duplexing (actual inheritance/temp inheritance) can be offset by setting these lines of code together.

Thirdly, when setting out your prototype, rather than set the whole thing (and overwriting the prototype you have just faked), writing it out longhand to add each item to the prototype adds a few more keystrokes but, if done in the correct order, I've found can yield 99% working intellisense at all times.

eg

if ($methodThatAlwaysReturnsFalse())

{

   MyNamespace.Stuff.prototype = Sys.xxxx.yyyy.prototype // Fake inheritance

}

...

MyNamespace.Stuff.prototype._myVar = null;

MyNamespace.Stuff.prototype.foo = function()

{

   this._myVar; // intellisense now enabled

   this.initialize(); // inherited methods are also available.

...

}

# July 22, 2008 7:07 PM
Leave a Comment

(required) 

(required) 

(optional)

(required)