jsdoc3/jsdoc — pull request #280 by mathematicalcoffee (2012-12-10 23:57:40+00:00)
Title: Nested events don't have longname set properly if order of tags is wrong.

# Problem

Nested events don't have longname set properly if order of tags is wrong.

In particular, using the following two tags to define a nested event in any order:

@eventname MyEvent
@memberof Container

OR the following three tags, where `@event` occurs *after* `@name` in any order (so `@name/@event/@memberOf`, `@name/@memberof/@event` and `@memberof/@event/@name`):

@name MyEvent
@event
@memberof Container

does not work.

In the above, the output doclet's name is set to 'MyEvent', the memberof to 'Container' (as expected), **but** the longname is set to 'event:MyEvent' instead of 'Container.event:MyEvent'.

# Test file

Consider the following: a set of events named A to I, all belonging to MyClass. We test all permutations of orders of `@event/@name/@memberof`, `@event [name]/@memberof`, and `@event Container.MyEvent` (i.e. fully resolved `@event` with no `@memberof`):

/** A class.
* @class */
var MyClass = {
/** WORKS
* @event
* @name A
* @memberof MyClass
*/
/** WORKS
* @event
* @memberof MyClass
* @name B
*/
/** DOESN'T WORK
* @name C
* @event
* @memberof MyClass
*/
/** DOESN'T WORK
* @name D
* @memberof MyClass
* @event
*/
/** WORKS
* @memberof MyClass
* @event
* @name E
*/
/** DOESN'T WORK
* @memberof MyClass
* @name F
* @event
*/

// @event syntax doesn.t work.
/** DOESN'T WORK
* @event G
* @memberof MyClass */
/** DOESN'T WORK
* @memberof MyClass
* @event H */

// Using full name works.
/** WORKS
* @event MyClass.I */
};

In the above, only events A, B, E and I come out with longnames `MyClass.event:[event name]` as expected. The others turn out with longname `event:[MyClass]`.

# Cause

It appears that for the `memberof` be appropriately prepended to the `longname`, we require that `doclet.name` is **undefined** when the `@event` tag is encountered.

This is because:

### Step 1
In `onTagged` of `@event`, `applyNamespace` is called with the doclet (`definitions.js`). If `doclet.name` is **undefined**, the call does nothing - once the doclet has finished parsing (and before `doclet.postProcess` is called), the doclet has the following properties:

name: EventName
longname:
memberof: Container

However, if `doclet.name` is **defined**, `applyNamespace` takes effect and we get:

name: EventName
longname: event:EventName
memberof: Container

Note that `doclet.name` is undefined when `@event` is encountered only if `@event` has no name after it, *and* `@name` occurs *after* the `@event` tag.

### Step 2
Now at the end of parsing tags, `doclet.postProcess()` is called.
In particular, this calls `jsdoc.name.resolve` on the doclet, which resolves the name of the doclet.

### Step 3
Looking at `jsdoc.name.resolve`, we see down the end:

if (doclet.name && doclet.memberof && !doclet.longname) {
// code that eventually calls:
doclet.setLongname(doclet.memberof + punctuation + doclet.name)
}

So for the first case above, since `longname` is `undefined` we eventually end up with longname `Container.EventName` which is later converted to `Container.event:EventName` in `postProcess`.
This is good.

In the second case above, since `doclet.longname` is already defined, the namespace is never properly applied to the event. Hence instead of the desired `Container.event:EventName` as the longname, we get `event:EventName`.

# Fix
I found two ways to fix this. The submitted pull request has the first one (remove `applyNamespace` call). If you prefer the second one I can re-submit.

I have also added a number of tests for the `"resolve"` function testing various orders of `@event`, `@name` and `@memberof` (it's a bit overkill, but too many tests is better than too little).

### First way to fix
Removing the `applyNamespace` call in `@event.onTagged` fixes the bug.
This keeps the longname clear so that `resolve` can operate on it.

Are there adverse effects to keeping an event's longname clear? (there must be a reason the `applyNamespace` call was put in in the first place, right?) The tests are all passed but it could be that the appropriate test has not yet been written. Anyhow, I do not notice adverse effects currently, but then again I may not use JSDoc as others do.

### Second way to fix
In `exports.resolve` of `rhino_modules/jsdoc/name.js`:

If the doclet has 'event:' in its longname we simply delete it. This allows it to be re-resolved with respect to the doclet's `memberof` as in Step 3 above.