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. Manual cherry-pick of 95e3192525310b9f1567e034c22489da3a5847a1.
This commit is contained in:
parent
c9b12b09ec
commit
eaa2cfb807
@ -531,7 +531,8 @@ 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) {
|
||||||
|
|||||||
@ -319,11 +319,9 @@ function makeConstructorFinisher(parser) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We prefer the parent doclet because it has the correct kind, longname, and memberof.
|
||||||
|
// The child doclet might or might not have the correct kind, longname, and memberof.
|
||||||
combined = combineDoclets(parentDoclet, eventDoclet);
|
combined = combineDoclets(parentDoclet, eventDoclet);
|
||||||
combined.longname = parentDoclet.longname;
|
|
||||||
if (parentDoclet.memberof) {
|
|
||||||
combined.memberof = parentDoclet.memberof;
|
|
||||||
}
|
|
||||||
|
|
||||||
parser.addResult(combined);
|
parser.addResult(combined);
|
||||||
|
|
||||||
|
|||||||
15
packages/jsdoc/test/fixtures/interface-assignment.js
vendored
Normal file
15
packages/jsdoc/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
packages/jsdoc/test/fixtures/interface-implements2.js
vendored
Normal file
23
packages/jsdoc/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 {}
|
||||||
@ -54,6 +54,50 @@ describe('@interface tag', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('ES2015 classes as interfaces', () => {
|
||||||
|
const docSet2 = jsdoc.getDocSetFromFile('test/fixtures/interface-implements2.js');
|
||||||
|
const docSet3 = jsdoc.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(() => {
|
||||||
jsdoc.restoreTagDictionary();
|
jsdoc.restoreTagDictionary();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user