Jsdoc: Add option to report undocumented objects

Created on 26 Oct 2012  路  18Comments  路  Source: jsdoc/jsdoc

It would be wonderful to have an option to discover all undocumented objects (classes, properties, functions, etc) in a code base. The tool could optionally report and/or fail when it finds an undocumented object.

accepted feature

Most helpful comment

+1

Is anyone starting to work for it?

All 18 comments

Agreed, this would be very useful.

As part of this feature, we should accept include/exclude regexps that allow you to control which members are discovered. For example, you might want to exclude members whose names begin with an underscore.

Also, it'd be nice if you could exclude members based on info in the AST. For example, you might want to exclude all inner members. That could be a follow-on enhancement, though.

I haven't looked into this, but could this be implemented as a plugin?

Definitely--I should have mentioned that! Perhaps that'll make things easier for anyone who wants to take a crack at this.

+1

I don't think failing is good, but warnings would be.

Ideally I think it should document/list them in an auto namespace called "Undocumented", or "TODOUndocumented" or something like that.

On a side note for this issue I have something that might help someone as a reference for anyone working on it: I have a nearly finished (but not bug free) javascript code obfuscator that uses regular expressions to identify all existing functions, variables, members, namespaces, etc that can be found here: https://github.com/jeremykentbgross/EmpathicCivGameEngine/blob/master/private/CodeObfuscator.js

If you used the ideas here for a reference you could generate a master object map of 'existing' documentable items, and if you also keep an object map of the 'documented' features, the difference between the sets should be all the undocumented items that need to go in your 'undocumented' namespace.

I'd like to try implement this as a plugin (I have use for it), but have some questions:

  1. I can probably use symbolFound to find symbols with no comment so I know they're undocumented
  2. What should I do then?

    • report/fail: I can probably work out how to do this (is there any way to "wait until the end of parsing" before reporting? an event afterParse opposite to beforeParse? for the corner case where the user documents an object manually after defining it in the code by using @name

    • it'd be great to have a page 'Undocumented symbols' in the output documentation, but how would I generate this? by modifying the default template, or is that really beyond the scope of a plugin?

  3. another option is to add the symbols to a namespace "Undocumented" as @jeremykentbgross mentioned above, but is this OK? what if they are already in their own namespace, will this screw up other documentation (with links etc)?

cheers

@mathematicalcoffee Thanks for looking at this one!

The closest thing to the event you're looking for is fileComplete, which fires each time the parser is done with a file. However, there's no guarantee that a symbol won't be documented in another file. Perhaps we need a parseComplete event that fires after all files have been parsed. It'd be easy to add this to jsdoc/src/parser.js. (I'd welcome suggestions for a better event name, although I'd prefer not to use afterParse, which makes it sound like the complement of beforeParse.)

I'm a little uncomfortable with changing the namespace by default, for the reasons you mentioned. Perhaps we could just log info to the console by default, and move everything to a specific namespace only if the user supplies the namespace. There's no way for plugins to modify the template, so that would be the easiest way to get template output for this.

That points to another issue: There's currently no canonical way to provide configuration settings to a plugin. We may want a new pluginConf object in conf.json, so the settings for myPluginName can be defined in pluginConf.myPluginName. There shouldn't be any default plugin settings in conf.json.EXAMPLE, though.

Hmm, one more tricky thing. Suppose you've written the following code and comments:

/**
 * @namespace
 */
var MyNamespace = {
    /**
     * @memberof MyNamespace
     * @type {Object}
     * @property {String} foo - The foo property.
     */
    MyMember: {
        foo: 'hi'
    }
};

As far as the parser is concerned, you haven't documented the longname MyNamespace.MyMember.foo at all. Here's an abbreviated version of the output from jsdoc -X:

{
  "memberof": "MyNamespace",
  "type": {
    "names": [
      "Object"
    ]
  },
  "properties": [
    {
      "type": {
        "names": [
          "String"
        ]
      },
      "optional": null,
      "nullable": null,
      "variable": null,
      "defaultvalue": undefined,
      "description": "The foo property.",
      "name": "foo"
    }
  ],
  "name": "MyMember",
  "kind": "member",
  "scope": "static",
  "longname": "MyNamespace.MyMember"
},
{
  "undocumented": true,
  "name": "foo",
  "kind": "member",
  "memberof": "MyNamespace.MyMember",
  "scope": "static",
  "longname": "MyNamespace.MyMember.foo"
}

If memory serves, you run into a similar situation when you document something as an @event, which changes the longname. The parse tree might contain a doclet for MyClass#event:foo, plus an undocumented member MyClass#foo. (I haven't double-checked this, but I think that's approximately right.)

I'm not sure whether there's any way to handle all of these sorts of issues in one fell swoop. The plugin might need to address each of them individually.

Hmmm.

Re generating an index of undocumented symbols - given that there are existing issues for generating an index of events (#274) as well as an index of @todo (#268) there's probably a more general solution available here, or at least code that can be recycled to "generate an index of <doclet property>", so I will leave that for now and concentrate on discovering undocumented symbols. It looks trickier than I thought though given your last comment!

Yep, it's much trickier than it ought to be. It'd be ideal if the parse results didn't contain these not-really-undocumented symbols... Alas, they do, and I suspect that fixing this during the parse phase would be even harder than discovering this from a plugin.

The term "undocumented" in this context was meant to describe a symbol that does not have it's very own JSDoc block associated with it directly. It was not meant to say that there is no reference to that symbol from any other doc block, even if that reference describes and documents it completely.

It's really just an artefact of the process of parsing JSDoc documented code, meant to resolve the following scenario:

/** @name foo */
function bar() {
}

There are two symbols there, one is documented (a _virtual_ foo symbol) and one is not (a lexical bar symbol). The problem is that Rhino doesn't know about things that JSDoc considers "virtual" and so happily attaches the comment describing foo to the code defining bar. The JSDoc parser has try to fix this by detaching the code and comment, which results in the somewhat paradoxical documentation of a symbol being "undocumented". Maybe the word "uncommented" would have been better?

In any case, those symbols without their very own comments are not thrown away for two reasons. Firstly because that code can affect the calculated namepaths of things that they scope, and secondly because the output template _might_ want to mention those uncommented symbols. In fact the default template throws them away. But, in my opinion, _that_ is the place to handle the issue. I don't know why a plugin was thought to be the best way to go (and don't go and review the comments above to see who first suggested using a plugin either, because I definitely know it wasn't some guy named "micmath").

As for the tricky factor, I'm afraid it gets worse. Consider:

/**
 * @namespace
 * @property {String} foo - The foo property.
 */
var MyNamespace = {
    /**
     * The foo property?
     * @type {number}
     */
    foo: 'hi'
};

Now MyNamespace.foo _is_ documented (meaning it has it's very own doc block). So we see that the @property tag _describes_ something about MyNamespace (the fact that it has a property named "foo") but the doc block _documents_ MyNamespace.foo. It's left to the output template to decide the best way of resolving this contradiction. (Is foo a string or a number?) In fact the default template displays all the information, showing a string property and a number member.

Overall, I think the @property should be seen as a shortcut used in special cases, whereas the full doc block should be seen as the official way to document a symbol.

Nb JSDoc has been accused of being overly verbose or so I've heard, so shortcuts are probably welcomed by our users -- they are worth promoting, but they are just that: shortcuts to the more fully-featured and yes verbose way to doing it.

@micmath: Thanks for the explanation, and in particular for pointing out that symbols without comments can affect namepaths! You're right, we can't possibly throw those out in the middle of the parse phase.

Perhaps this could be implemented as a template change (contrary to some guys who definitely aren't named "micmath" and "hegemonic"!), but with the bulk of the code located within JSDoc's main code base, rather than within the default template itself. That way other template authors can use the code without copying and pasting all of it.

Here's yet another wrinkle to consider, which came up in #294.

Suppose you ask JSDoc to generate docs for this file (and _only_ this file):

/**
 * Do something.
 * @param {string} str - A string.
 */
NamespaceA.NamespaceB.doSomething = function(str) {
    // code
};

You've documented the only symbol, so everything is documented, right? Wrong. You also need to document NamespaceA and NamespaceA.Namespace.B, or JSDoc (quite reasonably) discards the docs for doSomething.

Given this issue and the others mentioned above, perhaps this would be the easiest way to fulfill the original request:

  1. At parse time, build a tree of all the symbols that the parser encounters. At a minimum, this would need to include each symbol's longname and type, as well as the source file (and probably some other stuff I'm not thinking of right now).
  2. Create TaffyDB versions of the symbol tree and doclet tree.
  3. For each longname in the symbol tree, check whether the symbol and its implied parents are documented. If not, add the undocumented symbols to a list.
  4. Report the undocumented symbols (perhaps simply by dumping a list to the console).

If that's a good strategy, then a plugin really would be the right way to go! A plugin could get all the information it needs from symbolFound and newDoclet events. Then, if we added the parseComplete event I mentioned earlier, the plugin could dump a report upon receiving that event.

Are there any news on this issue? I'm looking for a way to "lint" files for missing docblocks. I know it's a tricky issue but so far I haven't found anything at all that would help me out in this regard.

The only news is that it's currently targeted for JSDoc 3.3 (the next minor version after 3.2).

Retargeting for 3.4 because there's way too much stuff targeted for 3.3.

+1

Is anyone starting to work for it?

If you help me to understand how I can use Walker I'd like to develop this feature @hegemonic .

According to these conversations I understand you don't want to develop this feature before the 4.0 release started. Is there a possibility that I develop this feature but you will merge that PR when 4.0 release starts.

These are the processes I want to follow.

  1. Walker will traverse nodes according to user-defined arguments. Arguments may have been written in conf file or passing as an argument by the CLI . For class methods: jsdoc path --undocumented MethodDefinition

  2. It will check if leadingComments exist in the MethodDefinition node, if it is not, it will take to the method information.

  3. After taking the method information It will create an HTML file named like undocumented.html. It will write information about the MethodDefinition in this HTML.

Would somebody help me to implement these steps? It is hard to solve the source code with debugging it.

I support this being a native functionality of JSDoc.

That said, there is the ability to do this with ESLint.

(Just wanted to add the link to this conversation for reference.)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cowwoc picture cowwoc  路  29Comments

gajus picture gajus  路  15Comments

akkie picture akkie  路  52Comments

alphanull picture alphanull  路  15Comments

yagop picture yagop  路  13Comments