Jsdoc: Problem with inherited event definitions - do appear twice

Created on 11 Sep 2013  路  15Comments  路  Source: jsdoc/jsdoc

Lets say I have 2 AMD modules, with "modules/B" inheriting from "modules/A". In addition, "modules/A" has an event definition, for a custom event "belonging" to this module, defined like this:

/**
 * This is a utility class.
 * @class MyClass
 */
var myClass = function() {};

define("modules/A", ["myClass"], function (myClass) {

  /**
   * Event definition, event "belongs" to Module A
   * @event module:modules/A#customEvent
   */

  /**
   * My Superclass module
   * @module modules/A
   */
    var A = myClass(/** @lends module:modules/A.prototype */ {

        /**
         * Use this to make a module:modules/A
         * @constructs
         */
        constructor: function () { }

    });

    return A;

});

In "modules/B", there is no such Event definition:

define("modules/B", ["myClass", "modules/A"], function (myClass, moduleA) {

  /**
   * My Subclass module
   * @module modules/B
   * @extends module:modules/A
   * @requires module:modules/A
   */
   var B = myClass(moduleA, /** @lends module:modules/B.prototype */ {

      /**
       * Use this to make a module:modules/B
       * @constructs
       * @extends module:modules/A
       */
      constructor: function () { }

   });

   return B;

});

The event is stil being displayed in the resulting docs, marked as "inherited from modules/A". So far so good. But what bugs me that now, in the global "events" section, this event is displayed twice. (And if I use more Subclasses, an entry gets added for each of these)

Since this event is essentially the same thing fromthe same source, I think this is a bug, I would expect that this event would be only displayed once in the "events" section.

All 15 comments

I think the current behavior is reasonable. In this example, the classes modules/A and modules/B can both fire a customEvent, so it seems appropriate to make that clear in the "Events" section. Otherwise you might look at the "Events" section; assume that only modules/A could fire the event; and fail to handle the events from modules/B.

I think the issue here is that the _presentation_ is not clear--the default template makes it look like customEvent is being shown twice for no good reason. This will (eventually) be addressed by #43.

I think I must disagree here! The problem here is imho, that the custom event - which was only defined _once_ and is never overridden - does appear multiple times in the "Event" section. Right now, I have things like this in my Events section:

  • CustomEvent
  • CustomEvent
  • CustomEvent
  • CustomEvent

So these entries point to the respective SUBclasses which just inherited this same event. I think it is OK to document this inherited events in the actual Subclass doc page (just as it is now), BUT NOT in the global "events" section. Why I think this? Well, it is just the same event over and over, it always has the same path and it was actually only defined once. Or in other words: even if a subclass can also fire the superclass event, it is still the very same event.

In the global "events" section I would therefore expect that only the "original event" appears here, and NOT also the - duplicated - inherited ones. And if I click on such an entry I would expect to be taken to the original event definition.

I am also not sure how #43 will solve this, so imho the problem remains. The only workaround I can see is to actually detach the event definition from the module it "belongs" to, and define all events as global events. Not too optimal I think, bc then the docs won't be that accurate anymore, and important information would be missing then. Would be better than having 100s of duplicated events, but of course a better solution would be much preferred.

I looked into this again. It appears that JSDoc's current behavior varies depending on whether the event is attached to a module or a class.

Suppose you have a bass class (or module) A and a derived class (or module) B. Here's what happens right now:

  • For classes, events defined in class A _are not_ shown in class B. The "Events" navbar section links to class A only.
  • For modules, events defined in module A _are_ shown in module B. Also, the "Events" navbar section links to modules A and B.

This is kind of silly. And after looking at this more closely, I agree with you that we shouldn't show the same event over and over in the navbar.

But I also want to think about the right way to deal with inherited events in the docs for each class/module. A few of the questions I have in mind:

  • Should we just assume that the derived class fires the same events as the base class?
  • What if the derived class also has a @fires tag?
  • Should we assume that any events defined in a class (or module) are also fired by that class (or module)? If we make that assumption, how would you override it?

I may use this issue to make the behavior consistent and slim down the navbar, then file a separate issue to follow up on these other questions. For now, just reopening this issue.

Should we just assume that the derived class fires the same events as the base class?

Yes, I think so, at least if the docs in the Superclass are not overidden. And I would extend it also to consuming (ie @listens), not firing only.

What if the derived class also has a @fires tag?

Depends on what it fires? I'd say the following rule could make sense for displaying the event in the "Event" Section: "If two defined events have the same identifier, do not duplicate the entries in the events section, but include docs (with pointers to the inherited event definition) for the actual module / class page". Just as it works with modules right now (would implement the same behavior with classes, too)

With "identifer", I mean this: @event _module:mvvm/Model#model/status_

So, if two modules are firing / listening an event named "module:mvvm/Model#model/status", I would see that as an identical event that should not be duplicated in the events section.

Should we assume that any events defined in a class (or module) are also fired by that class (or module)?

I would extend that also to @listens. With my current scheme, I define an event either as:

a) "global", esp when the event is used by several classes / modules, and cannot be clearly assigned to just one module / class
b) "belonging to a module" - if that event is only (or at least mainly) used by a certain class / module. And I look rather for the act of _consuming_ events, not _firing_, but of course you could see it the other way around. Think both approaches are valid from my POV.

So the whole point - for me - for defining an event attached to a class/module is to highlight the fact that the module is in a way tied to a specific event.

What I assume, though is that an event with the same identifier _is_ the same event. But really, anything else wouldn't make too much sense?

If we make that assumption, how would you override it?

@event definition in the subclass? But again, redefining the same event is not what I would do at all. _Maybe_ that would make sense if I have an event, that is somewhat extended (eg additional params) in the subclass, but personally I do not have such a case (yet).

PS: also reminds me a bit of #434 - I just see that it was closed, but does not seem to be solved?

Maybe these two issues have similar roots? (other one is also about inheriting)

I have the same problem when documenting classes that inherit from one another. I see a list of the same events duplicated for each class that extends the base class.

@hegemonic, this behavior differs from the behavior described in your comment above:

  • Events defined in class A are shown in class B.
  • The "Events" navbar section contains links to class A and class B for each event

I am documenting in the following style:

Component = new Class(/** @lends Component# */{
  /**
    @classdesc The base class for all components

    @desc Creates a new component
    @constructs Component
  */
  construct: function(options) {
    // ...
  },

  /**
    Triggered when the component is shown

    @event Component#show

    @param {Object} event             Event object
    @param {Mixed}  event.component   The component that was shown
  */

  /**
    Triggered when the component is hidden

    @event Component#hide

    @param {Object} event             Event object
    @param {Mixed}  event.component   The component that was hidden
  */
});

SubComponent = Component.extend(/** @lends SubComponent# */{
  /**
    @extends Component
    @classdesc A sub component

    @desc Creates a new sub component
    @constructs SubComponent

    @param {Object}   options   Component options
  */
  construct: function() {
    // ...
  }
});

Note: I am using @param instead of @property as it more directly documents the parameters passed to event listeners. The usejsdoc.org site says to use @param and specify @type as well, but that doesn't produce meaningful documentation.

So when will this be fixed (if at all)?

Yes, this will be fixed, but I don't have an ETA.

OK, that's good to hear. Meanwhile I have found a sort of workaround, so if I define the event as static member:
@event module:mvvm/Model.model/:cid/status
instead of:
@event module:mvvm/Model#model/:cid/status
the events are not duplicated in the resulting docs.

Yes, this will be fixed, but I don't have an ETA.

Any news?

Also, the "Events" navbar section links to modules A and B.

Events are like methods and properties: they are declared by classes (or modules), and get inherited by subclasses.

Since the navbar doesn't have entries for methods or properties, it shouldn't list events either. In other words, the navbar should just list the classes (or modules), and you should click on a specific module to see its properties, methods, and events.

Actually, as @lazd says, having the events as static members (which they are, in a sense) fixes things adequately.

@lazd and @RubenVerborgh, marking events as static (or inner) members is a reasonable short-term solution. But as discussed above, it's probably fair to say that if ClassB inherits from ClassA, ClassB is likely to fire the same events as ClassA. That suggests that the events really ought to be documented as instance members. (There's also issue #433, which is about providing a setting that would tell JSDoc that static members should be inherited, too.)

I don't really agree with instance members; events are objects, used by different classes. So it's probably more like: if a class has a method that emits an event, subclasses inherits that method.

@RubenVerborgh It's true that events are not really "instance members" of a class. But JSDoc handles inheritance by looking for instance members of the parent class and cloning them to the subclass. That makes it (relatively) easy to reason about what's inherited: Instance members are inherited, and everything else is not.

It would certainly be possible to look at all the static/inner members as well, then discard anything that's not an event, but I'm not convinced that the benefits would justify the added complexity.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

gocreating picture gocreating  路  18Comments

vcshox picture vcshox  路  13Comments

adrian-moisa picture adrian-moisa  路  19Comments

yagop picture yagop  路  13Comments

opvasger picture opvasger  路  31Comments