From c9b12b09ec5c99e71b3554ae892b12fac22196e2 Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Wed, 22 Jul 2020 16:54:53 -0700 Subject: [PATCH] fix: prevent circular refs when params have the same type expression Catharsis caches parse results by default; if you parse the same type expression twice, with the same options, you get the same object each time. When the user passes the `--debug` flag, we expose the parsed type for each parameter as an enumerable property of the doclet. If two parameters used the same type expression, the resulting doclet could contain a circular reference. This change disables the Catharsis cache, so that Catharsis returns a new object for each parsed type, which prevents circular references. As a result, this change fixes an issue with the `-X` flag, and with some JSDoc templates. --- packages/jsdoc/lib/jsdoc/tag/type.js | 5 +++- .../jsdoc/test/fixtures/paramtagsametype.js | 16 +++++++++++ .../specs/documentation/paramtagsametype.js | 28 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 packages/jsdoc/test/fixtures/paramtagsametype.js create mode 100644 packages/jsdoc/test/specs/documentation/paramtagsametype.js diff --git a/packages/jsdoc/lib/jsdoc/tag/type.js b/packages/jsdoc/lib/jsdoc/tag/type.js index de382070..5a143235 100644 --- a/packages/jsdoc/lib/jsdoc/tag/type.js +++ b/packages/jsdoc/lib/jsdoc/tag/type.js @@ -234,7 +234,10 @@ function parseTypeExpression(tagInfo) { } try { - parsedType = catharsis.parse(tagInfo.typeExpression, {jsdoc: true}); + parsedType = catharsis.parse(tagInfo.typeExpression, { + jsdoc: true, + useCache: false + }); } catch (e) { // always re-throw so the caller has a chance to report which file was bad diff --git a/packages/jsdoc/test/fixtures/paramtagsametype.js b/packages/jsdoc/test/fixtures/paramtagsametype.js new file mode 100644 index 00000000..70d9425b --- /dev/null +++ b/packages/jsdoc/test/fixtures/paramtagsametype.js @@ -0,0 +1,16 @@ +const foo = { + bar: {} +}; + +/** + * Baz class. + */ +foo.bar.Baz = class { + /** + * Creates a Baz. + * + * @param {string=} first - First parameter. + * @param {string=} second - Second parameter. + */ + constructor(first, second) {} +}; diff --git a/packages/jsdoc/test/specs/documentation/paramtagsametype.js b/packages/jsdoc/test/specs/documentation/paramtagsametype.js new file mode 100644 index 00000000..73e863cb --- /dev/null +++ b/packages/jsdoc/test/specs/documentation/paramtagsametype.js @@ -0,0 +1,28 @@ +const env = require('jsdoc/env'); + +describe('multiple @param tags with the same type expression', () => { + const debug = Boolean(env.opts.debug); + + afterEach(() => { + env.opts.debug = debug; + }); + + it('does not have circular references when type.parsedType is enumerable', () => { + let docSet; + let params; + let stringified; + + // Force type.parsedType to be enumerable. + env.opts.debug = true; + docSet = jsdoc.getDocSetFromFile('test/fixtures/paramtagsametype.js'); + params = docSet.getByLongname('foo.bar.Baz').filter(d => !d.undocumented)[0].params; + stringified = JSON.stringify(params); + + expect(stringified).toContain('"parsedType":'); + expect(stringified).not.toContain(''); + + // Prevent the schema validator from complaining about `parsedType`. (The schema _should_ + // allow that property, but for some reason, that doesn't work correctly.) + params.forEach(p => delete p.type.parsedType); + }); +});