mirror of
https://github.com/jsdoc/jsdoc.git
synced 2025-12-08 19:46:11 +00:00
fix: correctly track interface members
When an interface is a) defined as an ES2015 class and b) assigned to a variable, JSDoc sometimes used the wrong `longname` and `memberof` for members of the interface (specifically, for instance properties). The root cause was that we weren't resolving `this` correctly within this type of interface. As a result, if you added a JSDoc comment to something like `this.foo = 'bar'`, the doclet for `this.foo` had the wrong `longname` and `memberof`. Fixing that issue uncovered another issue: When we merged the constructor's doclet with the interface's doclet, we preferred the constructor's doclet. However, the constructor's doclet used the wrong `kind` in this case; we already had code to fix up the `longname` and `memberof` of the combined doclet, but not the `kind`. The fix was to prefer the interface's doclet for all properties.
This commit is contained in:
parent
ef05a69fc8
commit
95e3192525
@ -539,7 +539,7 @@ class Parser extends EventEmitter {
|
|||||||
result = doclet.longname;
|
result = doclet.longname;
|
||||||
}
|
}
|
||||||
// walk up to the closest class we can find
|
// walk up to the closest class we can find
|
||||||
else if (doclet.kind === 'class' || doclet.kind === 'module') {
|
else if (doclet.kind === 'class' || doclet.kind === 'interface' || doclet.kind === 'module') {
|
||||||
result = doclet.longname;
|
result = doclet.longname;
|
||||||
}
|
}
|
||||||
else if (node.enclosingScope) {
|
else if (node.enclosingScope) {
|
||||||
|
|||||||
@ -329,12 +329,9 @@ function makeConstructorFinisher(parser) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
combined = jsdoc.doclet.combine(doclet, parentDoclet);
|
// We prefer the parent doclet because it has the correct kind, longname, and memberof.
|
||||||
combined.longname = parentDoclet.longname;
|
// The child doclet might or might not have the correct kind, longname, and memberof.
|
||||||
if (parentDoclet.memberof) {
|
combined = jsdoc.doclet.combine(parentDoclet, doclet);
|
||||||
combined.memberof = parentDoclet.memberof;
|
|
||||||
}
|
|
||||||
|
|
||||||
parser.addResult(combined);
|
parser.addResult(combined);
|
||||||
|
|
||||||
parentDoclet.undocumented = doclet.undocumented = true;
|
parentDoclet.undocumented = doclet.undocumented = true;
|
||||||
|
|||||||
15
test/fixtures/interface-assignment.js
vendored
Normal file
15
test/fixtures/interface-assignment.js
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/** @namespace */
|
||||||
|
const myCorp = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @interface
|
||||||
|
*/
|
||||||
|
myCorp.IWorker = class IWorker {
|
||||||
|
constructor(workerName) {
|
||||||
|
/** Name of the worker. */
|
||||||
|
this.workerName = workerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Interface for doing some work. */
|
||||||
|
work() {}
|
||||||
|
};
|
||||||
23
test/fixtures/interface-implements2.js
vendored
Normal file
23
test/fixtures/interface-implements2.js
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* @interface
|
||||||
|
*/
|
||||||
|
class IWorker {
|
||||||
|
/** Interface for doing some work. */
|
||||||
|
work() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @implements {IWorker}
|
||||||
|
*/
|
||||||
|
class MyWorker {
|
||||||
|
/** Do some work. */
|
||||||
|
work() {}
|
||||||
|
|
||||||
|
/** Process a thing. */
|
||||||
|
process() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @implements {IWorker}
|
||||||
|
*/
|
||||||
|
class MyIncompleteWorker {}
|
||||||
@ -50,6 +50,50 @@ describe('@interface tag', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('ES2015 classes as interfaces', () => {
|
||||||
|
const docSet2 = jasmine.getDocSetFromFile('test/fixtures/interface-implements2.js');
|
||||||
|
const docSet3 = jasmine.getDocSetFromFile('test/fixtures/interface-assignment.js');
|
||||||
|
|
||||||
|
it('should set the correct kind on the interface', () => {
|
||||||
|
const workerInterface = docSet2.getByLongname('IWorker').filter(d => !d.undocumented)[0];
|
||||||
|
|
||||||
|
expect(workerInterface.kind).toBe('interface');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the correct kind on methods in the interface', () => {
|
||||||
|
const workerInterfaceWork = docSet2.getByLongname('IWorker#work')
|
||||||
|
.filter(d => !d.undocumented)[0];
|
||||||
|
|
||||||
|
expect(workerInterfaceWork.kind).toBe('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the correct kind on the implementing class', () => {
|
||||||
|
const workerImpl = docSet2.getByLongname('MyWorker').filter(d => !d.undocumented)[0];
|
||||||
|
|
||||||
|
expect(workerImpl.kind).toBe('class');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the correct kind on an interface assigned to a variable', () => {
|
||||||
|
const workerInterface = docSet3.getByLongname('myCorp.IWorker').filter(d => !d.undocumented)[0];
|
||||||
|
|
||||||
|
expect(workerInterface.kind).toBe('interface');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the correct kind on methods in an interface assigned to a variable', () => {
|
||||||
|
const workerInterfaceWork = docSet3.getByLongname('myCorp.IWorker#work')
|
||||||
|
.filter(d => !d.undocumented)[0];
|
||||||
|
|
||||||
|
expect(workerInterfaceWork.kind).toBe('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the correct kind on other members in an interface assigned to a variable', () => {
|
||||||
|
const workerName = docSet3.getByLongname('myCorp.IWorker#workerName')
|
||||||
|
.filter(d => !d.undocumented)[0];
|
||||||
|
|
||||||
|
expect(workerName.kind).toBe('member');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('Closure Compiler tags', () => {
|
describe('Closure Compiler tags', () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jasmine.restoreTagDictionary();
|
jasmine.restoreTagDictionary();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user