From 44b0862b8dbbe425df2fd3407d7a67d2ebdca64b Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Sat, 23 Oct 2021 11:59:57 -0700 Subject: [PATCH] refactor(jsdoc): eliminate global tag dictionary And remove final dependency on `jsdoc/env` outside `jsdoc.js`. In some cases, `jsdoc/util/templateHelper` functions now take a `dependencies` argument even when it looks like they could get the dependencies from a `doclet` parameter. That's because non-enumerable properties don't survive when the doclets are added to TaffyDB; as a result, the dependencies are no longer attached to each doclet by the time the template runs. This limitation should go away when we stop using TaffyDB. --- packages/jsdoc/cli.js | 4 ++ packages/jsdoc/lib/jsdoc/doclet.js | 19 +----- packages/jsdoc/lib/jsdoc/plugins.js | 3 +- packages/jsdoc/lib/jsdoc/tag.js | 19 +----- packages/jsdoc/lib/jsdoc/tag/dictionary.js | 11 +--- .../jsdoc/lib/jsdoc/util/templateHelper.js | 43 +++++-------- packages/jsdoc/templates/default/publish.js | 14 ++--- packages/jsdoc/test/helpers/jsdoc.js | 22 +++---- packages/jsdoc/test/specs/jsdoc/tag.js | 2 +- .../jsdoc/test/specs/jsdoc/tag/dictionary.js | 63 ++----------------- .../jsdoc/test/specs/jsdoc/tag/validator.js | 2 +- .../test/specs/jsdoc/util/templateHelper.js | 53 +++++++++++----- 12 files changed, 86 insertions(+), 169 deletions(-) diff --git a/packages/jsdoc/cli.js b/packages/jsdoc/cli.js index 57f2b2d2..3f8c31f3 100644 --- a/packages/jsdoc/cli.js +++ b/packages/jsdoc/cli.js @@ -1,6 +1,7 @@ /* eslint-disable indent, no-process-exit */ const _ = require('lodash'); const { config, Dependencies } = require('@jsdoc/core'); +const { Dictionary } = require('jsdoc/tag/dictionary'); const Engine = require('@jsdoc/cli'); const { EventBus, log } = require('@jsdoc/util'); const { Filter } = require('jsdoc/src/filter'); @@ -87,6 +88,9 @@ module.exports = (() => { // Now that we're done loading and merging things, register dependencies. dependencies.registerValue('config', env.conf); dependencies.registerValue('options', env.opts); + dependencies.registerSingletonFactory('tags', () => + Dictionary.fromConfig(dependencies.get('env')) + ); return cli; }; diff --git a/packages/jsdoc/lib/jsdoc/doclet.js b/packages/jsdoc/lib/jsdoc/doclet.js index 0623df1c..01b4e853 100644 --- a/packages/jsdoc/lib/jsdoc/doclet.js +++ b/packages/jsdoc/lib/jsdoc/doclet.js @@ -2,7 +2,6 @@ * @module jsdoc/doclet */ const _ = require('lodash'); -let dictionary = require('jsdoc/tag/dictionary'); const { isFunction } = require('@jsdoc/parse').astNode; const { applyNamespace, @@ -17,7 +16,6 @@ const { SCOPE_TO_PUNC, toParts, } = require('@jsdoc/core').name; -const helper = require('jsdoc/util/templateHelper'); const path = require('path'); const { Syntax } = require('@jsdoc/parse'); const tag = require('jsdoc/tag'); @@ -266,20 +264,6 @@ function resolve(doclet) { } } -/** - * Replace the existing tag dictionary with a new tag dictionary. - * - * Used for testing only. - * - * @private - * @param {module:jsdoc/tag/dictionary.Dictionary} dict - The new tag dictionary. - */ -exports._replaceDictionary = function _replaceDictionary(dict) { - dictionary = dict; - tag._replaceDictionary(dict); - helper._replaceDictionary(dict); -}; - function removeGlobal(longname) { const globalRegexp = new RegExp(`^${LONGNAMES.GLOBAL}\\.?`); @@ -447,6 +431,7 @@ class Doclet { * @param {string} [text] - The text of the tag being added. */ addTag(title, text) { + const dictionary = this.dependencies.get('tags'); const tagDef = dictionary.lookUp(title); const newTag = new Tag(title, text, this.meta, this.dependencies); @@ -481,6 +466,8 @@ class Doclet { * @param {string} longname - The longname for the doclet. */ setLongname(longname) { + const dictionary = this.dependencies.get('tags'); + /** * The fully resolved symbol name. * @type {string} diff --git a/packages/jsdoc/lib/jsdoc/plugins.js b/packages/jsdoc/lib/jsdoc/plugins.js index 78dbe833..52d80b1c 100644 --- a/packages/jsdoc/lib/jsdoc/plugins.js +++ b/packages/jsdoc/lib/jsdoc/plugins.js @@ -2,7 +2,6 @@ * Utility functions to support the JSDoc plugin framework. * @module jsdoc/plugins */ -const dictionary = require('jsdoc/tag/dictionary'); function addHandlers(handlers, parser, deps) { Object.keys(handlers).forEach((eventName) => { @@ -11,6 +10,7 @@ function addHandlers(handlers, parser, deps) { } exports.installPlugins = (plugins, parser, deps) => { + let dictionary; let plugin; for (let pluginModule of plugins) { @@ -24,6 +24,7 @@ exports.installPlugins = (plugins, parser, deps) => { // ...define tags if (plugin.defineTags) { + dictionary = deps.get('tags'); plugin.defineTags(dictionary, deps); } diff --git a/packages/jsdoc/lib/jsdoc/tag.js b/packages/jsdoc/lib/jsdoc/tag.js index 6fceaa80..7ca12d5c 100644 --- a/packages/jsdoc/lib/jsdoc/tag.js +++ b/packages/jsdoc/lib/jsdoc/tag.js @@ -6,7 +6,6 @@ const _ = require('lodash'); const { log } = require('@jsdoc/util'); const path = require('path'); const tag = { - dictionary: require('jsdoc/tag/dictionary'), validator: require('jsdoc/tag/validator'), type: require('@jsdoc/tag').type, }; @@ -119,19 +118,6 @@ function processTagText(tagInstance, tagDef, meta, dependencies) { } } -/** - * Replace the existing tag dictionary with a new tag dictionary. - * - * Used for testing only. Do not call this method directly. Instead, call - * {@link module:jsdoc/doclet._replaceDictionary}, which also updates this module's tag dictionary. - * - * @private - * @param {module:jsdoc/tag/dictionary.Dictionary} dict - The new tag dictionary. - */ -exports._replaceDictionary = function _replaceDictionary(dict) { - tag.dictionary = dict; -}; - /** * Represents a single doclet tag. */ @@ -145,6 +131,7 @@ class Tag { * @param {object} dependencies */ constructor(tagTitle, tagBody, meta, dependencies) { + const dictionary = dependencies.get('tags'); let tagDef; let trimOpts; @@ -154,9 +141,9 @@ class Tag { this.originalTitle = trim(tagTitle); /** The title of the tag (for example, `title` in `@title text`). */ - this.title = tag.dictionary.normalize(this.originalTitle); + this.title = dictionary.normalize(this.originalTitle); - tagDef = tag.dictionary.lookUp(this.title); + tagDef = dictionary.lookUp(this.title); trimOpts = { keepsWhitespace: tagDef.keepsWhitespace, removesIndent: tagDef.removesIndent, diff --git a/packages/jsdoc/lib/jsdoc/tag/dictionary.js b/packages/jsdoc/lib/jsdoc/tag/dictionary.js index ffa41b87..e8a0298a 100644 --- a/packages/jsdoc/lib/jsdoc/tag/dictionary.js +++ b/packages/jsdoc/lib/jsdoc/tag/dictionary.js @@ -1,6 +1,5 @@ /** @module jsdoc/tag/dictionary */ const definitions = require('jsdoc/tag/dictionary/definitions'); -const jsdocEnv = require('jsdoc/env'); const { log } = require('@jsdoc/util'); const hasOwnProp = Object.prototype.hasOwnProperty; @@ -10,8 +9,6 @@ const DEFINITIONS = { jsdoc: 'jsdocTags', }; -let dictionary; - /** @private */ class TagDefinition { constructor(dict, title, etc) { @@ -173,11 +170,5 @@ class Dictionary { } } -// initialize the default dictionary -dictionary = Dictionary.fromConfig(jsdocEnv); - -// make the constructor available for unit-testing purposes -dictionary.Dictionary = Dictionary; - /** @type {module:jsdoc/tag/dictionary.Dictionary} */ -module.exports = dictionary; +exports.Dictionary = Dictionary; diff --git a/packages/jsdoc/lib/jsdoc/util/templateHelper.js b/packages/jsdoc/lib/jsdoc/util/templateHelper.js index c4b7d2a8..5c244e1f 100644 --- a/packages/jsdoc/lib/jsdoc/util/templateHelper.js +++ b/packages/jsdoc/lib/jsdoc/util/templateHelper.js @@ -2,7 +2,6 @@ * @module jsdoc/util/templateHelper */ const catharsis = require('catharsis'); -let dictionary = require('jsdoc/tag/dictionary'); const { inline } = require('@jsdoc/tag'); const { log } = require('@jsdoc/util'); const { longnamesToTree, SCOPE, SCOPE_TO_PUNC, toParts } = require('@jsdoc/core').name; @@ -42,7 +41,7 @@ const registerId = (exports.registerId = (longname, fragment) => { linkMap.longnameToId[longname] = fragment; }); -function getNamespace(kind) { +function getNamespace(kind, dictionary) { if (dictionary.isNamespace(kind)) { return `${kind}:`; } @@ -50,8 +49,10 @@ function getNamespace(kind) { return ''; } -function formatNameForLink(doclet) { - let newName = getNamespace(doclet.kind) + (doclet.name || '') + (doclet.variation || ''); +function formatNameForLink(doclet, dependencies) { + const dictionary = dependencies.get('tags'); + let newName = + getNamespace(doclet.kind, dictionary) + (doclet.name || '') + (doclet.variation || ''); const scopePunc = SCOPE_TO_PUNC[doclet.scope] || ''; // Only prepend the scope punctuation if it's not the same character that marks the start of a @@ -100,9 +101,11 @@ function makeUniqueFilename(filename, str) { * * @function * @param {string} str The string to convert. + * @param {Object} dependencies The JSDoc dependency container. * @return {string} The filename to use for the string. */ -const getUniqueFilename = (exports.getUniqueFilename = (str) => { +const getUniqueFilename = (exports.getUniqueFilename = (str, dependencies) => { + const dictionary = dependencies.get('tags'); const namespaces = dictionary.getNamespaces().join('|'); let basename = (str || '') // use - instead of : in namespace prefixes @@ -131,13 +134,13 @@ const getUniqueFilename = (exports.getUniqueFilename = (str) => { * register the filename. * @private */ -function getFilename(longname) { +function getFilename(longname, dependencies) { let fileUrl; if (hasOwnProp.call(longnameToUrl, longname)) { fileUrl = longnameToUrl[longname]; } else { - fileUrl = getUniqueFilename(longname); + fileUrl = getUniqueFilename(longname, dependencies); registerLink(longname, fileUrl); } @@ -852,9 +855,10 @@ exports.prune = (data, dependencies) => { * represents a method), the URL will consist of a filename and a fragment ID. * * @param {module:jsdoc/doclet.Doclet} doclet - The doclet that will be used to create the URL. + * @param {Object} dependencies - The JSDoc dependency container. * @return {string} The URL to the generated documentation for the doclet. */ -exports.createLink = (doclet) => { +exports.createLink = (doclet, dependencies) => { let fakeContainer; let filename; let fileUrl; @@ -875,21 +879,21 @@ exports.createLink = (doclet) => { // the doclet gets its own HTML file if (containers.includes(doclet.kind) || isModuleExports(doclet)) { - filename = getFilename(longname); + filename = getFilename(longname, dependencies); } // mistagged version of a doclet that gets its own HTML file else if (!containers.includes(doclet.kind) && fakeContainer) { - filename = getFilename(doclet.memberof || longname); + filename = getFilename(doclet.memberof || longname, dependencies); if (doclet.name !== doclet.longname) { - fragment = formatNameForLink(doclet); + fragment = formatNameForLink(doclet, dependencies); fragment = getId(longname, fragment); } } // the doclet is within another HTML file else { - filename = getFilename(doclet.memberof || exports.globalName); + filename = getFilename(doclet.memberof || exports.globalName, dependencies); if (doclet.name !== doclet.longname || doclet.scope === SCOPE.NAMES.GLOBAL) { - fragment = formatNameForLink(doclet); + fragment = formatNameForLink(doclet, dependencies); fragment = getId(longname, fragment); } } @@ -912,16 +916,3 @@ exports.createLink = (doclet) => { * @return {Object} A tree with information about each longname. */ exports.longnamesToTree = longnamesToTree; - -/** - * Replace the existing tag dictionary with a new tag dictionary. - * - * Used for testing only. Do not call this method directly. Instead, call - * {@link module:jsdoc/doclet._replaceDictionary}, which also updates this module's tag dictionary. - * - * @private - * @param {module:jsdoc/tag/dictionary.Dictionary} dict - The new tag dictionary. - */ -exports._replaceDictionary = function _replaceDictionary(dict) { - dictionary = dict; -}; diff --git a/packages/jsdoc/templates/default/publish.js b/packages/jsdoc/templates/default/publish.js index a356b46b..c4ca0085 100644 --- a/packages/jsdoc/templates/default/publish.js +++ b/packages/jsdoc/templates/default/publish.js @@ -39,14 +39,14 @@ function getAncestorLinks(doclet) { return helper.getAncestorLinks(data, doclet); } -function hashToLink(doclet, hash) { +function hashToLink(doclet, hash, dependencies) { let url; if (!/^(#.+)/.test(hash)) { return hash; } - url = helper.createLink(doclet); + url = helper.createLink(doclet, dependencies); url = url.replace(/(#.+|$)/, hash); return `${hash}`; @@ -254,7 +254,7 @@ function generateSourceFiles(sourceFiles, encoding, outdir, dependencies) { Object.keys(sourceFiles).forEach((file) => { let source; // links are keyed to the shortened path in each doclet's `meta.shortpath` property - const sourceOutfile = helper.getUniqueFilename(sourceFiles[file].shortened); + const sourceOutfile = helper.getUniqueFilename(sourceFiles[file].shortened, dependencies); helper.registerLink(sourceFiles[file].shortened, sourceOutfile); @@ -452,10 +452,10 @@ exports.publish = (taffyData, dependencies) => { // claim some special filenames in advance, so the All-Powerful Overseer of Filename Uniqueness // doesn't try to hand them out later - indexUrl = helper.getUniqueFilename('index'); + indexUrl = helper.getUniqueFilename('index', dependencies); // don't call registerLink() on this one! 'index' is also a valid longname - globalUrl = helper.getUniqueFilename('global'); + globalUrl = helper.getUniqueFilename('global', dependencies); helper.registerLink('global', globalUrl); // set up templating @@ -490,7 +490,7 @@ exports.publish = (taffyData, dependencies) => { } if (doclet.see) { doclet.see.forEach((seeItem, i) => { - doclet.see[i] = hashToLink(doclet, seeItem); + doclet.see[i] = hashToLink(doclet, seeItem, dependencies); }); } @@ -595,7 +595,7 @@ exports.publish = (taffyData, dependencies) => { } data().each((doclet) => { let docletPath; - const url = helper.createLink(doclet); + const url = helper.createLink(doclet, dependencies); helper.registerLink(doclet.longname, url); diff --git a/packages/jsdoc/test/helpers/jsdoc.js b/packages/jsdoc/test/helpers/jsdoc.js index cab619b1..5da12b8d 100644 --- a/packages/jsdoc/test/helpers/jsdoc.js +++ b/packages/jsdoc/test/helpers/jsdoc.js @@ -1,14 +1,12 @@ -const { _replaceDictionary } = require('jsdoc/doclet'); const { augmentAll } = require('jsdoc/augment'); const { createParser } = require('jsdoc/src/parser'); -const { Dictionary } = require('jsdoc/tag/dictionary'); const { EventBus } = require('@jsdoc/util'); const fs = require('fs'); const handlers = require('jsdoc/src/handlers'); const path = require('path'); const bus = new EventBus('jsdoc'); -let originalDictionaries; +const originalDictionaries = ['jsdoc', 'closure']; const parseResults = []; const helpers = { @@ -63,26 +61,20 @@ const helpers = { }, getParseResults: () => parseResults, replaceTagDictionary: (dictionaryNames) => { - let dict; - const env = jsdoc.deps.get('env'); + const config = jsdoc.deps.get('config'); if (!Array.isArray(dictionaryNames)) { dictionaryNames = [dictionaryNames]; } - originalDictionaries = env.conf.tags.dictionaries.slice(); - env.conf.tags.dictionaries = dictionaryNames; - - dict = Dictionary.fromConfig(env); - dict.Dictionary = Dictionary; - _replaceDictionary(dict); - - env.conf.tags.dictionaries = originalDictionaries; + config.tags.dictionaries = dictionaryNames; + jsdoc.deps.reset('tags'); }, restoreTagDictionary: () => { - const env = jsdoc.deps.get('env'); + const config = jsdoc.deps.get('config'); - _replaceDictionary(Dictionary.fromConfig(env)); + config.tags.dictionaries = originalDictionaries.slice(); + jsdoc.deps.reset('tags'); }, }; diff --git a/packages/jsdoc/test/specs/jsdoc/tag.js b/packages/jsdoc/test/specs/jsdoc/tag.js index c2f0049e..6dabfc03 100644 --- a/packages/jsdoc/test/specs/jsdoc/tag.js +++ b/packages/jsdoc/test/specs/jsdoc/tag.js @@ -2,7 +2,7 @@ const hasOwnProp = Object.prototype.hasOwnProperty; const options = jsdoc.deps.get('options'); describe('jsdoc/tag', () => { - const jsdocDictionary = require('jsdoc/tag/dictionary'); + const jsdocDictionary = jsdoc.deps.get('tags'); const jsdocTag = require('jsdoc/tag'); const parseType = require('@jsdoc/tag').type.parse; diff --git a/packages/jsdoc/test/specs/jsdoc/tag/dictionary.js b/packages/jsdoc/test/specs/jsdoc/tag/dictionary.js index 679336a2..f40ceffa 100644 --- a/packages/jsdoc/test/specs/jsdoc/tag/dictionary.js +++ b/packages/jsdoc/test/specs/jsdoc/tag/dictionary.js @@ -1,6 +1,5 @@ describe('jsdoc/tag/dictionary', () => { - const dictionary = require('jsdoc/tag/dictionary'); - const Dictionary = dictionary.Dictionary; + const { Dictionary } = require('jsdoc/tag/dictionary'); const env = jsdoc.deps.get('env'); let testDictionary; @@ -17,56 +16,12 @@ describe('jsdoc/tag/dictionary', () => { TAG_DEF = testDictionary.defineTag(TAG_TITLE, tagOptions).synonym(TAG_SYNONYM); }); - it('is an instance of dictionary.Dictionary', () => { - expect(dictionary instanceof dictionary.Dictionary).toBe(true); - }); - - it('has a defineSynonym method', () => { - expect(dictionary.defineSynonym).toBeFunction(); - }); - - it('has a defineTag method', () => { - expect(dictionary.defineTag).toBeFunction(); - }); - - it('has a defineTags method', () => { - expect(dictionary.defineTags).toBeFunction(); - }); - - it('has a fromConfig static method', () => { - expect(dictionary.Dictionary.fromConfig).toBeFunction(); - }); - - it('has a lookup method', () => { - expect(dictionary.lookup).toBeFunction(); - }); - - it('has a lookUp method', () => { - expect(dictionary.lookUp).toBeFunction(); - }); - - it('has an isNamespace method', () => { - expect(dictionary.isNamespace).toBeFunction(); - }); - - it('has a normalise method', () => { - expect(dictionary.normalise).toBeFunction(); - }); - - it('has a normalize method', () => { - expect(dictionary.normalize).toBeFunction(); - }); - - it('has a Dictionary constructor', () => { - expect(dictionary.Dictionary).toBeFunction(); - }); - describe('defineSynonym', () => { it('adds a synonym for the specified tag', () => { - dictionary.defineTag('foo', {}); - dictionary.defineSynonym('foo', 'bar'); + testDictionary.defineTag('foo', {}); + testDictionary.defineSynonym('foo', 'bar'); - expect(dictionary.normalize('bar')).toBe('foo'); + expect(testDictionary.normalize('bar')).toBe('foo'); }); }); @@ -274,14 +229,4 @@ describe('jsdoc/tag/dictionary', () => { expect(testDictionary.normalize(TAG_SYNONYM)).toBe(TAG_DEF.title); }); }); - - describe('Dictionary', () => { - it('is a constructor', () => { - function newDictionary() { - return new dictionary.Dictionary(); - } - - expect(newDictionary).not.toThrow(); - }); - }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/tag/validator.js b/packages/jsdoc/test/specs/jsdoc/tag/validator.js index ea6e2981..8329d517 100644 --- a/packages/jsdoc/test/specs/jsdoc/tag/validator.js +++ b/packages/jsdoc/test/specs/jsdoc/tag/validator.js @@ -15,7 +15,7 @@ describe('jsdoc/tag/validator', () => { }); describe('validate', () => { - const dictionary = require('jsdoc/tag/dictionary'); + const dictionary = jsdoc.deps.get('tags'); const allowUnknown = Boolean(config.tags.allowUnknownTags); const badTag = { dependencies: jsdoc.deps, title: 'lkjasdlkjfb' }; diff --git a/packages/jsdoc/test/specs/jsdoc/util/templateHelper.js b/packages/jsdoc/test/specs/jsdoc/util/templateHelper.js index 5a77626f..3ef2c50f 100644 --- a/packages/jsdoc/test/specs/jsdoc/util/templateHelper.js +++ b/packages/jsdoc/test/specs/jsdoc/util/templateHelper.js @@ -3,7 +3,8 @@ const hasOwnProp = Object.prototype.hasOwnProperty; describe('jsdoc/util/templateHelper', () => { const _ = require('lodash'); - const dictionary = require('jsdoc/tag/dictionary'); + const { Dependencies } = require('@jsdoc/core'); + const { Dictionary } = require('jsdoc/tag/dictionary'); const doclet = require('jsdoc/doclet'); const helper = require('jsdoc/util/templateHelper'); const { taffy } = require('taffydb'); @@ -139,31 +140,31 @@ describe('jsdoc/util/templateHelper', () => { // TODO: needs more tests for unusual values and things that get special treatment (such as // inner members) it('should convert a simple string into the string plus the default extension', () => { - const filename = helper.getUniqueFilename('BackusNaur'); + const filename = helper.getUniqueFilename('BackusNaur', jsdoc.deps); expect(filename).toBe('BackusNaur.html'); }); it('should replace slashes with underscores', () => { - const filename = helper.getUniqueFilename('tick/tock'); + const filename = helper.getUniqueFilename('tick/tock', jsdoc.deps); expect(filename).toBe('tick_tock.html'); }); it('should replace other problematic characters with underscores', () => { - const filename = helper.getUniqueFilename('a very strange \\/?*:|\'"<> filename'); + const filename = helper.getUniqueFilename('a very strange \\/?*:|\'"<> filename', jsdoc.deps); expect(filename).toBe('a very strange __________ filename.html'); }); it('should not allow a filename to start with an underscore', () => { - expect(helper.getUniqueFilename('')).toBe('-_.html'); + expect(helper.getUniqueFilename('', jsdoc.deps)).toBe('-_.html'); }); it('should not return the same filename twice', () => { const name = 'polymorphic'; - const filename1 = helper.getUniqueFilename(name); - const filename2 = helper.getUniqueFilename(name); + const filename1 = helper.getUniqueFilename(name, jsdoc.deps); + const filename2 = helper.getUniqueFilename(name, jsdoc.deps); expect(filename1).not.toBe(filename2); }); @@ -171,23 +172,26 @@ describe('jsdoc/util/templateHelper', () => { it('should not consider the same name with different letter case to be unique', () => { const camel = 'myJavaScriptIdentifier'; const pascal = 'MyJavaScriptIdentifier'; - const filename1 = helper.getUniqueFilename(camel); - const filename2 = helper.getUniqueFilename(pascal); + const filename1 = helper.getUniqueFilename(camel, jsdoc.deps); + const filename2 = helper.getUniqueFilename(pascal, jsdoc.deps); expect(filename1.toLowerCase()).not.toBe(filename2.toLowerCase()); }); it('should remove variations from the longname before generating the filename', () => { - const filename = helper.getUniqueFilename('MyClass(foo, bar)'); + const filename = helper.getUniqueFilename('MyClass(foo, bar)', jsdoc.deps); expect(filename).toBe('MyClass.html'); }); it('should generate the correct filename for built-in namespaces', () => { - const filenameEvent = helper.getUniqueFilename('event:userDidSomething'); - const filenameExternal = helper.getUniqueFilename('external:NotInThisPackage'); - const filenameModule = helper.getUniqueFilename('module:some/sort/of/module'); - const filenamePackage = helper.getUniqueFilename('package:node-solve-all-your-problems'); + const filenameEvent = helper.getUniqueFilename('event:userDidSomething', jsdoc.deps); + const filenameExternal = helper.getUniqueFilename('external:NotInThisPackage', jsdoc.deps); + const filenameModule = helper.getUniqueFilename('module:some/sort/of/module', jsdoc.deps); + const filenamePackage = helper.getUniqueFilename( + 'package:node-solve-all-your-problems', + jsdoc.deps + ); expect(filenameEvent).toBe('event-userDidSomething.html'); expect(filenameExternal).toBe('external-NotInThisPackage.html'); @@ -196,15 +200,16 @@ describe('jsdoc/util/templateHelper', () => { }); it('should generate the correct filename for user-specified namespaces', () => { + const deps = new Dependencies(); + const dict = new Dictionary(); let filename; - const dict = new dictionary.Dictionary(); dict.defineTag('anaphylaxis', { isNamespace: true, }); - doclet._replaceDictionary(dict); + deps.registerSingletonFactory('tags', () => dict); - filename = helper.getUniqueFilename('anaphylaxis:peanut'); + filename = helper.getUniqueFilename('anaphylaxis:peanut', deps); expect(filename).toBe('anaphylaxis-peanut.html'); }); @@ -1556,6 +1561,7 @@ describe('jsdoc/util/templateHelper', () => { describe('createLink', () => { it('should create a url for a simple global.', () => { const mockDoclet = { + dependencies: jsdoc.deps, kind: 'function', longname: 'foo', name: 'foo', @@ -1568,6 +1574,7 @@ describe('jsdoc/util/templateHelper', () => { it('should create a url for a namespace.', () => { const mockDoclet = { + dependencies: jsdoc.deps, kind: 'namespace', longname: 'foo', name: 'foo', @@ -1579,6 +1586,7 @@ describe('jsdoc/util/templateHelper', () => { it('should create a url for a member of a namespace.', () => { const mockDoclet = { + dependencies: jsdoc.deps, kind: 'function', longname: 'ns.foo', name: 'foo', @@ -1590,6 +1598,7 @@ describe('jsdoc/util/templateHelper', () => { }); const nestedNamespaceDoclet = { + dependencies: jsdoc.deps, kind: 'function', longname: 'ns1.ns2.foo', name: 'foo', @@ -1611,6 +1620,7 @@ describe('jsdoc/util/templateHelper', () => { it('should create a url for a name with invalid characters.', () => { const mockDoclet = { + dependencies: jsdoc.deps, kind: 'function', longname: 'ns1."!"."*foo"', name: '"*foo"', @@ -1623,6 +1633,7 @@ describe('jsdoc/util/templateHelper', () => { it('should create a url for a function that is the only symbol exported by a module.', () => { const mockDoclet = { + dependencies: jsdoc.deps, kind: 'function', longname: 'module:bar', name: 'module:bar', @@ -1634,11 +1645,13 @@ describe('jsdoc/util/templateHelper', () => { it('should create a url for a doclet with the wrong kind (caused by incorrect JSDoc tags', () => { const moduleDoclet = { + dependencies: jsdoc.deps, kind: 'module', longname: 'module:baz', name: 'module:baz', }; const badDoclet = { + dependencies: jsdoc.deps, kind: 'member', longname: 'module:baz', name: 'module:baz', @@ -1652,11 +1665,13 @@ describe('jsdoc/util/templateHelper', () => { it('should create a url for a function that is a member of a doclet with the wrong kind', () => { const badModuleDoclet = { + dependencies: jsdoc.deps, kind: 'member', longname: 'module:qux', name: 'module:qux', }; const memberDoclet = { + dependencies: jsdoc.deps, kind: 'function', name: 'frozzle', memberof: 'module:qux', @@ -1672,6 +1687,7 @@ describe('jsdoc/util/templateHelper', () => { it('should include the scope punctuation in the fragment ID for static members', () => { const functionDoclet = { + dependencies: jsdoc.deps, kind: 'function', longname: 'Milk.pasteurize', name: 'pasteurize', @@ -1685,6 +1701,7 @@ describe('jsdoc/util/templateHelper', () => { it('should include the scope punctuation in the fragment ID for inner members', () => { const functionDoclet = { + dependencies: jsdoc.deps, kind: 'function', longname: 'Milk~removeSticksAndLeaves', name: 'removeSticksAndLeaves', @@ -1698,6 +1715,7 @@ describe('jsdoc/util/templateHelper', () => { it('should omit the scope punctuation from the fragment ID for instance members', () => { const propertyDoclet = { + dependencies: jsdoc.deps, kind: 'member', longname: 'Milk#calcium', name: 'calcium', @@ -1711,6 +1729,7 @@ describe('jsdoc/util/templateHelper', () => { it('should include the variation, if present, in the fragment ID', () => { const variationDoclet = { + dependencies: jsdoc.deps, kind: 'function', longname: 'Milk#fat(percent)', name: 'fat',