Skip to content

Commit

Permalink
Ensure that ES 2015 classes appear in the generated docs when they're…
Browse files Browse the repository at this point in the history
… supposed to. (#1644)

Previously, when we combined doclets, we copied the `undocumented` property if it was set to `true`. That caused the combined doclet to have this property set to `true`, although it shouldn't have. As a result, the template discarded the doclet.

The solution is to simply ignore this property when combining doclets.

Also includes related cleanup for clarity.
  • Loading branch information
hegemonic committed May 12, 2019
1 parent 03b8abd commit 61ae11c
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 70 deletions.
49 changes: 24 additions & 25 deletions lib/jsdoc/doclet.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,17 +209,16 @@ function dooper(source, target, properties) {
}

/**
* Combine two doclets into a target doclet, using properties from the secondary doclet only when
* those properties do not exist on the primary doclet, and ignoring properties that should be
* excluded.
* Copy all but a list of excluded properties from one of two doclets onto a target doclet. Prefers
* the primary doclet over the secondary doclet.
*
* @private
* @param {module:jsdoc/doclet.Doclet} primary - The primary doclet.
* @param {module:jsdoc/doclet.Doclet} secondary - The secondary doclet.
* @param {module:jsdoc/doclet.Doclet} target - The doclet to which properties will be copied.
* @param {Array.<string>} exclude - The names of properties to exclude from copying.
*/
function combine(primary, secondary, target, exclude) {
function copyMostProperties(primary, secondary, target, exclude) {
const primaryProperties = _.difference(Object.getOwnPropertyNames(primary), exclude);
const secondaryProperties = _.difference(Object.getOwnPropertyNames(secondary),
exclude.concat(primaryProperties));
Expand All @@ -229,34 +228,24 @@ function combine(primary, secondary, target, exclude) {
}

/**
* Combine specified properties from two doclets into a target doclet, using the properties of the
* primary doclet unless the properties of the secondary doclet appear to be a better fit.
* Copy specific properties from one of two doclets onto a target doclet, as long as the property
* has a non-falsy value and a length greater than 0. Prefers the primary doclet over the secondary
* doclet.
*
* @private
* @param {module:jsdoc/doclet.Doclet} primary - The primary doclet.
* @param {module:jsdoc/doclet.Doclet} secondary - The secondary doclet.
* @param {module:jsdoc/doclet.Doclet} target - The doclet to which properties will be copied.
* @param {Array.<string>} include - The names of properties to copy.
*/
function combineWithLogic(primary, secondary, target, include) {
function copySpecificProperties(primary, secondary, target, include) {
include.forEach(property => {
let shouldUsePrimary = false;

if ({}.hasOwnProperty.call(primary, property)) {
// use the primary property if the secondary property is missing or empty
if (!secondary[property] || !secondary[property].length) {
shouldUsePrimary = true;
}
// use the source property if it's not empty
else if (primary[property].length) {
shouldUsePrimary = true;
}
}

if (shouldUsePrimary) {
if ({}.hasOwnProperty.call(primary, property) && primary[property] &&
primary[property].length) {
target[property] = jsdoc.util.doop(primary[property]);
}
else if ({}.hasOwnProperty.call(secondary, property)) {
else if ({}.hasOwnProperty.call(secondary, property) && secondary[property] &&
secondary[property].length) {
target[property] = jsdoc.util.doop(secondary[property]);
}
});
Expand Down Expand Up @@ -548,16 +537,26 @@ exports.Doclet = Doclet;
* @param {module:jsdoc/doclet.Doclet} primary - The doclet whose properties will be used.
* @param {module:jsdoc/doclet.Doclet} secondary - The doclet to use as a fallback for properties
* that the primary doclet does not have.
* @returns {module:jsdoc/doclet.Doclet} A new doclet that combines the primary and secondary
* doclets.
*/
exports.combine = (primary, secondary) => {
const specialCase = [
const copyMostPropertiesExclude = [
'params',
'properties',
'undocumented'
];
const copySpecificPropertiesInclude = [
'params',
'properties'
];
const target = new Doclet('');

combine(primary, secondary, target, specialCase);
combineWithLogic(primary, secondary, target, specialCase);
// First, copy most properties to the target doclet.
copyMostProperties(primary, secondary, target, copyMostPropertiesExclude);
// Then copy a few specific properties to the target doclet, as long as they're not falsy and
// have a length greater than 0.
copySpecificProperties(primary, secondary, target, copySpecificPropertiesInclude);

return target;
};
43 changes: 31 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

88 changes: 55 additions & 33 deletions test/specs/jsdoc/doclet.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,68 +48,90 @@ describe('jsdoc/doclet', () => {
});
});

// TODO(hegemonic): More tests.
describe('combine', () => {
it('should override most properties of the secondary doclet', () => {
const primaryDoclet = new Doclet('/** New and improved!\n@version 2.0.0 */');
const secondaryDoclet = new Doclet('/** Hello!\n@version 1.0.0 */');
it('overrides most properties of the secondary doclet', () => {
const primaryDoclet = new Doclet(`
/**
* New and improved!
* @version 2.0.0
*/`);
const secondaryDoclet = new Doclet(`
/**
* Hello!
* @version 1.0.0
*/`);
const newDoclet = jsdoc.doclet.combine(primaryDoclet, secondaryDoclet);

Object.getOwnPropertyNames(newDoclet).forEach(property => {
expect(newDoclet[property]).toEqual(primaryDoclet[property]);
});
});

it('should add properties that are missing from the secondary doclet', () => {
const primaryDoclet = new Doclet('/** Hello!\n@version 2.0.0 */');
const secondaryDoclet = new Doclet('/** Hello! */');
it('adds properties that are missing from the secondary doclet', () => {
const primaryDoclet = new Doclet(`
/**
* Hello!
* @version 2.0.0
*/`);
const secondaryDoclet = new Doclet(`
/**
* Hello!
*/`);
const newDoclet = jsdoc.doclet.combine(primaryDoclet, secondaryDoclet);

expect(newDoclet.version).toBe('2.0.0');
});

it('ignores the property `undocumented`', () => {
const primaryDoclet = new Doclet('/** Hello! */');
const secondaryDoclet = new Doclet('/** Hello again! */');
let newDoclet;

primaryDoclet.undocumented = true;
secondaryDoclet.undocumented = true;

newDoclet = jsdoc.doclet.combine(primaryDoclet, secondaryDoclet);

expect(newDoclet.undocumented).not.toBeDefined();
});

describe('params and properties', () => {
const properties = [
'params',
'properties'
];

it('should use the secondary doclet\'s params and properties if the primary doclet ' +
'had none', () => {
const primaryDoclet = new Doclet('/** Hello! */');
const secondaryComment = [
'/**',
' * @param {string} foo - The foo.',
' * @property {number} bar - The bar.',
' */'
].join('\n');
const secondaryDoclet = new Doclet(secondaryComment);
it('uses the primary doclet\'s params and properties if present', () => {
const primaryDoclet = new Doclet(`
/**
* @param {number} baz - The baz.
* @property {string} qux - The qux.
*/`);
const secondaryDoclet = new Doclet(`
/**
* @param {string} foo - The foo.
* @property {number} bar - The bar.
*/`);
const newDoclet = jsdoc.doclet.combine(primaryDoclet, secondaryDoclet);

properties.forEach(property => {
expect(newDoclet[property]).toEqual(secondaryDoclet[property]);
expect(newDoclet[property]).toEqual(primaryDoclet[property]);
});
});

it('should use the primary doclet\'s params and properties if the primary doclet has ' +
'some', () => {
const primaryComment = [
'/**',
' * @param {number} baz - The baz.',
' * @property {string} qux - The qux.',
' */'
].join('\n');
const primaryDoclet = new Doclet(primaryComment);
const secondaryComment = [
'/**',
' * @param {string} foo - The foo.',
' * @property {number} bar - The bar.',
' */'
].join('\n');
it('uses the secondary doclet\'s params and properties if necessary', () => {
const primaryDoclet = new Doclet('/** Hello! */');
const secondaryComment = `
/**
* @param {string} foo - The foo.
* @property {number} bar - The bar.
*/`;
const secondaryDoclet = new Doclet(secondaryComment);
const newDoclet = jsdoc.doclet.combine(primaryDoclet, secondaryDoclet);

properties.forEach(property => {
expect(newDoclet[property]).toEqual(primaryDoclet[property]);
expect(newDoclet[property]).toEqual(secondaryDoclet[property]);
});
});
});
Expand Down

0 comments on commit 61ae11c

Please sign in to comment.