eslint/doctrine

Reported line numbers are sometimes incorrect

TEHEK opened this issue · 4 comments

TEHEK commented
let comment = `
/**
 * Test class
 * @extends {BaseClass}
 * @constructor
 * @param {string} name
 */
`;

doctrine.parse(comment, {unwrap: true, lineNumbers: true});


{ description: '/**\nTest class',
  tags: 
   [ { title: 'extends',
       description: null,
       lineNumber: 3,
       type: [Object],
       name: null },
     { title: 'constructor',
       description: null,
       lineNumber: 5,
       type: null,
       name: null },
     { title: 'param',
       description: '/',
       lineNumber: 7,
       type: [Object],
       name: 'name' } ] }

Constructor's lineNumber is 5, but should be 4.
Param's lineNumber is 7. Should be 5

Also, notice the param's description.

TEHEK commented

A little experiment:

'use strict';

var doctrine = require('../lib/doctrine');

var Rules = {
    // http://usejsdoc.org/tags-access.html
    'access': ['parseAccess'],
    // http://usejsdoc.org/tags-alias.html
    'alias': ['parseNamePath', 'ensureEnd'],
    // http://usejsdoc.org/tags-augments.html
    'augments': ['parseType', 'parseNamePathOptional', 'ensureEnd'],
    // http://usejsdoc.org/tags-constructor.html
    'constructor': ['parseType', 'parseNamePathOptional', 'ensureEnd'],
    // Synonym: http://usejsdoc.org/tags-constructor.html
    'class': ['parseType', 'parseNamePathOptional', 'ensureEnd'],
    // Synonym: http://usejsdoc.org/tags-extends.html
    'extends': ['parseType', 'parseNamePathOptional', 'ensureEnd'],
    // http://usejsdoc.org/tags-deprecated.html
    'deprecated': ['parseDescription'],
    // http://usejsdoc.org/tags-global.html
    'global': ['ensureEnd'],
    // http://usejsdoc.org/tags-inner.html
    'inner': ['ensureEnd'],
    // http://usejsdoc.org/tags-instance.html
    'instance': ['ensureEnd'],
    // http://usejsdoc.org/tags-kind.html
    'kind': ['parseKind'],
    // http://usejsdoc.org/tags-mixes.html
    'mixes': ['parseNamePath', 'ensureEnd'],
    // http://usejsdoc.org/tags-mixin.html
    'mixin': ['parseNamePathOptional', 'ensureEnd'],
    // http://usejsdoc.org/tags-member.html
    'member': ['parseType', 'parseNamePathOptional', 'ensureEnd'],
    // http://usejsdoc.org/tags-method.html
    'method': ['parseNamePathOptional', 'ensureEnd'],
    // http://usejsdoc.org/tags-module.html
    'module': ['parseType', 'parseNamePathOptional', 'ensureEnd'],
    // Synonym: http://usejsdoc.org/tags-method.html
    'func': ['parseNamePathOptional', 'ensureEnd'],
    // Synonym: http://usejsdoc.org/tags-method.html
    'function': ['parseNamePathOptional', 'ensureEnd'],
    // Synonym: http://usejsdoc.org/tags-member.html
    'var': ['parseType', 'parseNamePathOptional', 'ensureEnd'],
    // http://usejsdoc.org/tags-name.html
    'name': ['parseNamePath', 'ensureEnd'],
    // http://usejsdoc.org/tags-namespace.html
    'namespace': ['parseType', 'parseNamePathOptional', 'ensureEnd'],
    // http://usejsdoc.org/tags-private.html
    'private': ['parseType', 'parseDescription'],
    // http://usejsdoc.org/tags-protected.html
    'protected': ['parseType', 'parseDescription'],
    // http://usejsdoc.org/tags-public.html
    'public': ['parseType', 'parseDescription'],
    // http://usejsdoc.org/tags-readonly.html
    'readonly': ['ensureEnd'],
    // http://usejsdoc.org/tags-requires.html
    'requires': ['parseNamePath', 'ensureEnd'],
    // http://usejsdoc.org/tags-since.html
    'since': ['parseDescription'],
    // http://usejsdoc.org/tags-static.html
    'static': ['ensureEnd'],
    // http://usejsdoc.org/tags-summary.html
    'summary': ['parseDescription'],
    // http://usejsdoc.org/tags-this.html
    'this': ['parseNamePath', 'ensureEnd'],
    // http://usejsdoc.org/tags-todo.html
    'todo': ['parseDescription'],
    // http://usejsdoc.org/tags-typedef.html
    'typedef': ['parseType', 'parseNamePathOptional'],
    // http://usejsdoc.org/tags-variation.html
    'variation': ['parseVariation'],
    // http://usejsdoc.org/tags-version.html
    'version': ['parseDescription']
};

for (var tag in Rules) {
  var comment = [
    '/**',
    ' * @' + tag,
    ' * @dummy',
    ' */'
  ].join('\n');
  var t = doctrine.parse(comment, {unwrap: true, sloppy: true, lineNumbers: true});
  if (t.tags[1] && t.tags[1].lineNumber != 2) {
    console.error('Wrong: ', tag);
    continue;
  }
  console.log('OK:   ', tag);
}

Prints:

OK:     access
OK:     alias
Wrong:  augments
Wrong:  constructor
Wrong:  class
Wrong:  extends
OK:     deprecated
OK:     global
OK:     inner
OK:     instance
OK:     kind
OK:     mixes
Wrong:  mixin
Wrong:  member
Wrong:  method
Wrong:  module
Wrong:  func
Wrong:  function
Wrong:  var
OK:     name
Wrong:  namespace
OK:     private
OK:     protected
OK:     public
OK:     readonly
OK:     requires
OK:     since
OK:     static
OK:     summary
OK:     this
OK:     todo
OK:     typedef
OK:     variation
OK:     version

I suspect that parseNamePathOptional is responsible.

The line number should be 5 because you have an initial newline right after the back tick. So "@constructor" is actually on line 5. That said, "@param" should be on line 6, so this looks like parameter parsing is the root problem.

TEHEK commented

Yes, there's a new line, but that shouldn't count as it is outside the jsdoc comment.

Ah, good point!