From 3025520e156f072bb6de6939193213353dc0c810 Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Sat, 18 Sep 2021 12:07:10 -0700 Subject: [PATCH] refactor(jsdoc): shift functionality into tag dictionaries With an eye towards removing the `jsdoc/env` dependency later. Notable changes include: + `Dictionary` now has methods to define tags. (Those methods used to be tied to the tag definitions, which seems backwards to me.) + `Dictionary` now has a `fromConfig()` static method that takes `jsdoc/env` as an argument and returns a new dictionary that's set up appropriately. --- packages/jsdoc/lib/jsdoc/doclet.js | 8 +- packages/jsdoc/lib/jsdoc/tag/dictionary.js | 108 +++++++--- .../lib/jsdoc/tag/dictionary/definitions.js | 132 ++---------- packages/jsdoc/test/helpers/jsdoc.js | 13 +- .../jsdoc/test/specs/jsdoc/tag/dictionary.js | 199 +++++++++++++++--- .../specs/jsdoc/tag/dictionary/definitions.js | 109 +--------- .../test/specs/jsdoc/util/templateHelper.js | 2 - 7 files changed, 298 insertions(+), 273 deletions(-) diff --git a/packages/jsdoc/lib/jsdoc/doclet.js b/packages/jsdoc/lib/jsdoc/doclet.js index c7b7fcf8..de4edf22 100644 --- a/packages/jsdoc/lib/jsdoc/doclet.js +++ b/packages/jsdoc/lib/jsdoc/doclet.js @@ -17,9 +17,11 @@ 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'); +const tag = require('jsdoc/tag'); +const Tag = tag.Tag; const DEFAULT_SCOPE = SCOPE.NAMES.STATIC; @@ -282,8 +284,8 @@ function resolve(doclet) { */ exports._replaceDictionary = function _replaceDictionary(dict) { dictionary = dict; - require('jsdoc/tag')._replaceDictionary(dict); - require('jsdoc/util/templateHelper')._replaceDictionary(dict); + tag._replaceDictionary(dict); + helper._replaceDictionary(dict); }; function removeGlobal(longname) { diff --git a/packages/jsdoc/lib/jsdoc/tag/dictionary.js b/packages/jsdoc/lib/jsdoc/tag/dictionary.js index 8d2e1aaa..14f4a5e8 100644 --- a/packages/jsdoc/lib/jsdoc/tag/dictionary.js +++ b/packages/jsdoc/lib/jsdoc/tag/dictionary.js @@ -1,8 +1,15 @@ /** @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; +const DEFINITIONS = { + closure: 'closureTags', + jsdoc: 'jsdocTags' +}; + let dictionary; /** @private */ @@ -12,7 +19,7 @@ class TagDefinition { etc = etc || {}; - this.title = dict.normalise(title); + this.title = dict.normalize(title); Object.defineProperty(this, '_dictionary', { value: dict @@ -36,15 +43,19 @@ class TagDefinition { */ class Dictionary { constructor() { + // TODO: Consider adding internal tags in the constructor, ideally as fallbacks that aren't + // used to confirm whether a tag is defined/valid, rather than requiring every set of tag + // definitions to contain the internal tags. this._tags = {}; this._tagSynonyms = {}; - // The longnames for `Package` objects include a `package` namespace. There's no `package` tag, - // though, so we declare the namespace here. + // The longnames for `Package` objects include a `package` namespace. There's no `package` + // tag, though, so we declare the namespace here. + // TODO: Consider making this a fallback as suggested above for internal tags. this._namespaces = ['package']; } _defineNamespace(title) { - title = this.normalise(title || ''); + title = this.normalize(title || ''); if (title && !this._namespaces.includes(title)) { this._namespaces.push(title); @@ -58,34 +69,70 @@ class Dictionary { this._tags[tagDef.title] = tagDef; - if (opts && opts.isNamespace) { + if (tagDef.isNamespace) { this._defineNamespace(tagDef.title); } + if (tagDef.synonyms) { + tagDef.synonyms.forEach(synonym => { + this.defineSynonym(title, synonym); + }); + } return this._tags[tagDef.title]; } + defineTags(tagDefs) { + const tags = {}; + + for (const title of Object.keys(tagDefs)) { + tags[title] = this.defineTag(title, tagDefs[title]); + } + + return tags; + } + defineSynonym(title, synonym) { - this._tagSynonyms[synonym.toLowerCase()] = this.normalise(title); + this._tagSynonyms[synonym.toLowerCase()] = this.normalize(title); + } + + static fromConfig(env) { + let dictionaries = env.conf.tags.dictionaries; + const dict = new Dictionary(); + + if (!dictionaries) { + log.error( + 'The configuration setting "tags.dictionaries" is undefined. ' + + 'Unable to load tag definitions.' + ); + } else { + dictionaries.slice().reverse().forEach(dictName => { + const tagDefs = definitions[DEFINITIONS[dictName]]; + + if (!tagDefs) { + log.error( + 'The configuration setting "tags.dictionaries" contains ' + + `the unknown dictionary name ${dictName}. Ignoring the dictionary.` + ); + + return; + } + + dict.defineTags(tagDefs); + }); + + dict.defineTags(definitions.internalTags); + } + + return dict; } getNamespaces() { - return this._namespaces.slice(0); - } - - lookUp(title) { - title = this.normalise(title); - - if ( hasOwnProp.call(this._tags, title) ) { - return this._tags[title]; - } - - return false; + return this._namespaces.slice(); } isNamespace(kind) { if (kind) { - kind = this.normalise(kind); + kind = this.normalize(kind); if (this._namespaces.includes(kind)) { return true; } @@ -94,7 +141,25 @@ class Dictionary { return false; } + lookup(title) { + title = this.normalize(title); + + if ( hasOwnProp.call(this._tags, title) ) { + return this._tags[title]; + } + + return false; + } + + lookUp(title) { + return this.lookup(title); + } + normalise(title) { + return this.normalize(title); + } + + normalize(title) { const canonicalName = title.toLowerCase(); if ( hasOwnProp.call(this._tagSynonyms, canonicalName) ) { @@ -103,15 +168,10 @@ class Dictionary { return canonicalName; } - - normalize(title) { - return this.normalise(title); - } } // initialize the default dictionary -dictionary = new Dictionary(); -definitions.defineTags(dictionary); +dictionary = Dictionary.fromConfig(jsdocEnv); // make the constructor available for unit-testing purposes dictionary.Dictionary = Dictionary; diff --git a/packages/jsdoc/lib/jsdoc/tag/dictionary/definitions.js b/packages/jsdoc/lib/jsdoc/tag/dictionary/definitions.js index 0a97f64b..5f7649b9 100644 --- a/packages/jsdoc/lib/jsdoc/tag/dictionary/definitions.js +++ b/packages/jsdoc/lib/jsdoc/tag/dictionary/definitions.js @@ -15,11 +15,12 @@ const parseTagType = require('@jsdoc/tag').type.parse; const hasOwnProp = Object.prototype.hasOwnProperty; -const DEFINITIONS = { - closure: 'closureTags', - jsdoc: 'jsdocTags' -}; const MODULE_NAMESPACE = 'module:'; +const NOOP_TAG = { + onTagged: () => { + // Do nothing. + } +}; // Clone a tag definition, excluding synonyms. function cloneTagDef(tagDef, extras) { @@ -214,7 +215,7 @@ function combineTypes({value}) { } // Tags that JSDoc uses internally, and that must always be defined. -const internalTags = { +const internalTags = exports.internalTags = { // Special separator tag indicating that multiple doclets should be generated for the same // comment. Used internally (and by some JSDoc users, although it's not officially supported). // In the following example, the parser will replace `//**` with an `@also` tag: @@ -855,10 +856,6 @@ baseTags = _.extend(baseTags, internalTags); // Tag dictionary for JSDoc. exports.jsdocTags = baseTags; -function ignore() { - // do nothing -} - // Tag dictionary for Google Closure Compiler. exports.closureTags = { const: { @@ -873,18 +870,12 @@ exports.closureTags = { constructor: cloneTagDef(baseTags.class), deprecated: cloneTagDef(baseTags.deprecated), // Closure Compiler only - dict: { - onTagged: ignore - }, + dict: NOOP_TAG, enum: cloneTagDef(baseTags.enum), // Closure Compiler only - export: { - onTagged: ignore - }, + export: NOOP_TAG, // Closure Compiler only - externs: { - onTagged: ignore - }, + externs: NOOP_TAG, extends: cloneTagDef(baseTags.augments), fileoverview: { onTagged(doclet, tag) { @@ -898,9 +889,7 @@ exports.closureTags = { final: cloneTagDef(baseTags.readonly), implements: cloneTagDef(baseTags.implements), // Closure Compiler only - implicitcast: { - onTagged: ignore - }, + implicitcast: NOOP_TAG, inheritdoc: cloneTagDef(baseTags.inheritdoc), interface: cloneTagDef(baseTags.interface, { canHaveName: false, @@ -912,17 +901,11 @@ exports.closureTags = { license: cloneTagDef(baseTags.license), modifies: cloneTagDef(baseTags.modifies), // Closure Compiler only - noalias: { - onTagged: ignore - }, + noalias: NOOP_TAG, // Closure Compiler only - nocollapse: { - onTagged: ignore - }, + nocollapse: NOOP_TAG, // Closure Compiler only - nocompile: { - onTagged: ignore - }, + nocompile: NOOP_TAG, // Closure Compiler only nosideeffects: { onTagged(doclet) { @@ -948,13 +931,9 @@ exports.closureTags = { }, param: cloneTagDef(baseTags.param), // Closure Compiler only - polymer: { - onTagged: ignore - }, + polymer: NOOP_TAG, // Closure Compiler only - polymerBehavior: { - onTagged: ignore - }, + polymerBehavior: NOOP_TAG, // Closure Compiler only preserve: cloneTagDef(baseTags.license), private: { @@ -989,17 +968,11 @@ exports.closureTags = { }, return: cloneTagDef(baseTags.returns), // Closure Compiler only - struct: { - onTagged: ignore - }, + struct: NOOP_TAG, // Closure Compiler only - suppress: { - onTagged: ignore - }, + suppress: NOOP_TAG, // Closure Compiler only - template: { - onTagged: ignore - }, + template: NOOP_TAG, 'this': { canHaveType: true, onTagged(doclet, tag) { @@ -1018,72 +991,5 @@ exports.closureTags = { } }, // Closure Compiler only - unrestricted: { - onTagged: ignore - } -}; - -function addTagDefinitions(dictionary, tagDefs) { - Object.keys(tagDefs).forEach(tagName => { - let tagDef; - - tagDef = tagDefs[tagName]; - dictionary.defineTag(tagName, tagDef); - - if (tagDef.synonyms) { - tagDef.synonyms.forEach(synonym => { - dictionary.defineSynonym(tagName, synonym); - }); - } - }); -} - -/** - * Populate the given dictionary with the appropriate JSDoc tag definitions. - * - * If the `tagDefinitions` parameter is omitted, JSDoc uses its configuration settings to decide - * which tags to add to the dictionary. - * - * If the `tagDefinitions` parameter is included, JSDoc adds only the tag definitions from the - * `tagDefinitions` object. The configuration settings are ignored. - * - * @param {module:jsdoc/tag/dictionary} dictionary - * @param {Object} [tagDefinitions] - A dictionary whose values define the rules for a JSDoc tag. - */ -exports.defineTags = (dictionary, tagDefinitions) => { - let dictionaries; - - if (!tagDefinitions) { - dictionaries = env.conf.tags.dictionaries; - - if (!dictionaries) { - log.error( - 'The configuration setting "tags.dictionaries" is undefined. ' + - 'Unable to load tag definitions.' - ); - - return; - } - else { - dictionaries = dictionaries.slice(0).reverse(); - } - - dictionaries.forEach(dictName => { - const tagDefs = exports[DEFINITIONS[dictName]]; - - if (!tagDefs) { - log.error( - 'The configuration setting "tags.dictionaries" contains ' + - `the unknown dictionary name ${dictName}. Ignoring the dictionary.` - ); - - return; - } - - addTagDefinitions(dictionary, _.extend(tagDefs, internalTags)); - }); - } - else { - addTagDefinitions(dictionary, _.extend(tagDefinitions, internalTags)); - } + unrestricted: NOOP_TAG }; diff --git a/packages/jsdoc/test/helpers/jsdoc.js b/packages/jsdoc/test/helpers/jsdoc.js index 8775cec9..1b68dd57 100644 --- a/packages/jsdoc/test/helpers/jsdoc.js +++ b/packages/jsdoc/test/helpers/jsdoc.js @@ -1,8 +1,7 @@ const { _replaceDictionary } = require('jsdoc/doclet'); const { augmentAll } = require('jsdoc/augment'); const { createParser } = require('jsdoc/src/parser'); -const { defineTags } = require('jsdoc/tag/dictionary/definitions'); -const dictionary = require('jsdoc/tag/dictionary'); +const { Dictionary } = require('jsdoc/tag/dictionary'); const env = require('jsdoc/env'); const { EventBus } = require('@jsdoc/util'); const fs = require('fs'); @@ -10,7 +9,7 @@ const handlers = require('jsdoc/src/handlers'); const path = require('path'); const bus = new EventBus('jsdoc'); -const originalDictionary = dictionary; +const originalDictionaries = env.conf.tags.dictionaries.slice(); const parseResults = []; const helpers = global.jsdoc = { @@ -65,8 +64,7 @@ const helpers = global.jsdoc = { }, getParseResults: () => parseResults, replaceTagDictionary: dictionaryNames => { - const dict = new dictionary.Dictionary(); - const originalDictionaries = env.conf.tags.dictionaries.slice(0); + let dict; if (!Array.isArray(dictionaryNames)) { dictionaryNames = [dictionaryNames]; @@ -74,12 +72,13 @@ const helpers = global.jsdoc = { env.conf.tags.dictionaries = dictionaryNames; - defineTags(dict); + dict = Dictionary.fromConfig(env); + dict.Dictionary = Dictionary; _replaceDictionary(dict); env.conf.tags.dictionaries = originalDictionaries; }, restoreTagDictionary: () => { - _replaceDictionary(originalDictionary); + _replaceDictionary(Dictionary.fromConfig(env)); } }; diff --git a/packages/jsdoc/test/specs/jsdoc/tag/dictionary.js b/packages/jsdoc/test/specs/jsdoc/tag/dictionary.js index 9b4ddb30..0cc22f66 100644 --- a/packages/jsdoc/test/specs/jsdoc/tag/dictionary.js +++ b/packages/jsdoc/test/specs/jsdoc/tag/dictionary.js @@ -1,48 +1,63 @@ describe('jsdoc/tag/dictionary', () => { const dictionary = require('jsdoc/tag/dictionary'); - const testDictionary = new dictionary.Dictionary(); + const Dictionary = dictionary.Dictionary; + const env = require('jsdoc/env'); + let testDictionary; const tagOptions = { canHaveValue: true, isNamespace: true }; - const TAG_TITLE = '!!!testTag!!!'; + let TAG_DEF; const TAG_SYNONYM = '!!!testTagSynonym!!!'; - const TAG_DEF = testDictionary.defineTag(TAG_TITLE, tagOptions).synonym(TAG_SYNONYM); + const TAG_TITLE = '!!!testTag!!!'; - it('should exist', () => { - expect(dictionary).toBeObject(); + beforeEach(() => { + testDictionary = new Dictionary(); + TAG_DEF = testDictionary.defineTag(TAG_TITLE, tagOptions).synonym(TAG_SYNONYM); }); - it('should be an instance of dictionary.Dictionary', () => { + it('is an instance of dictionary.Dictionary', () => { expect(dictionary instanceof dictionary.Dictionary).toBe(true); }); - it('should export a defineSynonym method', () => { + it('has a defineSynonym method', () => { expect(dictionary.defineSynonym).toBeFunction(); }); - it('should export a defineTag method', () => { + it('has a defineTag method', () => { expect(dictionary.defineTag).toBeFunction(); }); - it('should export a lookUp method', () => { + 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('should export an isNamespace method', () => { + it('has an isNamespace method', () => { expect(dictionary.isNamespace).toBeFunction(); }); - it('should export a normalise method', () => { + it('has a normalise method', () => { expect(dictionary.normalise).toBeFunction(); }); - it('should export a normalize method', () => { + it('has a normalize method', () => { expect(dictionary.normalize).toBeFunction(); }); - it('should export a Dictionary constructor', () => { + it('has a Dictionary constructor', () => { expect(dictionary.Dictionary).toBeFunction(); }); @@ -77,19 +92,147 @@ describe('jsdoc/tag/dictionary', () => { expect(makeTag).not.toThrow(); expect(makeTag().title).toBe(testDictionary.normalize(NEW_TITLE)); }); + + it('adds synonyms', () => { + const tagDef = { + mustHaveValue: true, + synonyms: ['bar'] + }; + + testDictionary.defineTag('foo', tagDef); + + expect(testDictionary.normalize('bar')).toBe('foo'); + }); }); - describe('lookUp', () => { + describe('defineTags', () => { + it('behaves the same as adding tags individually', () => { + const dict1 = new Dictionary(); + const dict2 = new Dictionary(); + const fakeTag = { + mustHaveValue: true, + synonym: 'phony' + }; + + dict1.defineTag('fake', fakeTag); + dict2.defineTags({ fake: fakeTag }); + + expect(dict2.lookup('fake')).toEqual(dict1.lookup('fake')); + expect(dict2.lookup('phony')).toEqual(dict1.lookup('phony')); + }); + + it('returns the tags it added', () => { + const tags = { + tag1: { + tag1Attribute: 'foo' + }, + tag2: { + tag2Attribute: 'bar' + } + }; + const actualTags = testDictionary.defineTags(tags); + + for (const tag of Object.keys(tags)) { + expect(actualTags[tag]).toBeObject(); + for (const attrib of Object.keys(tags[tag])) { + expect(tags[tag][attrib]).toBe(actualTags[tag][attrib]); + } + } + }); + }); + + describe('fromConfig', () => { + const CLOSURE_TAGNAME = 'final'; + const dictionaryConfig = env.conf.tags.dictionaries.slice(); + const JSDOC_TAGNAME = 'abstract'; + + beforeEach(() => { + env.conf.tags.dictionaries = []; + }); + + afterEach(() => { + env.conf.tags.dictionaries = dictionaryConfig.slice(); + }); + + it('logs an error if `env.conf.tags.dictionaries` is undefined', () => { + function defineTags() { + env.conf.tags.dictionaries = undefined; + Dictionary.fromConfig(env); + } + + expect(jsdoc.didLog(defineTags, 'error')).toBeTrue(); + }); + + it('logs an error if an unknown dictionary is requested', () => { + function defineTags() { + env.conf.tags.dictionaries = ['jsmarmoset']; + Dictionary.fromConfig(env); + } + + expect(jsdoc.didLog(defineTags, 'error')).toBeTrue(); + }); + + it('adds both JSDoc and Closure tags by default', () => { + env.conf.tags.dictionaries = dictionaryConfig.slice(); + testDictionary = Dictionary.fromConfig(env); + + expect(testDictionary.lookup(JSDOC_TAGNAME)).toBeObject(); + expect(testDictionary.lookup(CLOSURE_TAGNAME)).toBeObject(); + }); + + it('adds only the JSDoc tags if requested', () => { + env.conf.tags.dictionaries = ['jsdoc']; + testDictionary = Dictionary.fromConfig(env); + + expect(testDictionary.lookup(JSDOC_TAGNAME)).toBeObject(); + expect(testDictionary.lookup(CLOSURE_TAGNAME)).toBeFalse(); + }); + + it('adds only the Closure tags if requested', () => { + env.conf.tags.dictionaries = ['closure']; + testDictionary = Dictionary.fromConfig(env); + + expect(testDictionary.lookup(JSDOC_TAGNAME)).toBeFalse(); + expect(testDictionary.lookup(CLOSURE_TAGNAME)).toBeObject(); + }); + + it('prefers tagdefs from the first dictionary on the list', () => { + env.conf.tags.dictionaries = ['closure', 'jsdoc']; + testDictionary = Dictionary.fromConfig(env); + + expect(testDictionary.lookup('deprecated').synonyms).not.toBeDefined(); + }); + + it('adds tag synonyms', () => { + env.conf.tags.dictionaries = ['jsdoc']; + testDictionary = Dictionary.fromConfig(env); + + expect(testDictionary.lookup('extends')).toBeObject(); + expect(testDictionary.normalize('extends')).toBe('augments'); + }); + }); + + describe('lookup', () => { it("retrieves the definition using the tag's canonical name", () => { - expect(testDictionary.lookUp(TAG_TITLE)).toBe(TAG_DEF); + expect(testDictionary.lookup(TAG_TITLE)).toBe(TAG_DEF); }); it('retrieves the definition using a synonym for the tag', () => { - expect(testDictionary.lookUp(TAG_SYNONYM)).toBe(TAG_DEF); + expect(testDictionary.lookup(TAG_SYNONYM)).toBe(TAG_DEF); }); it('returns `false` when a tag is not found', () => { - expect(testDictionary.lookUp('lkjas1l24jk')).toBeFalse(); + expect(testDictionary.lookup('lkjas1l24jk')).toBeFalse(); + }); + }); + + describe('lookUp', () => { + it('calls `lookup`', () => { + const lookupSpy = spyOn(testDictionary, 'lookup'); + + testDictionary.lookUp('foo'); + + expect(lookupSpy).toHaveBeenCalled(); }); }); @@ -112,22 +255,28 @@ describe('jsdoc/tag/dictionary', () => { }); describe('normalise', () => { - it("should return the tag's title if it is not a synonym", () => { - expect(testDictionary.normalise('FooBar')).toBe('foobar'); - expect(testDictionary.normalise(TAG_TITLE)).toBe(TAG_DEF.title); - }); + it('calls `normalize`', () => { + const normalizeSpy = spyOn(testDictionary, 'normalize'); - it('should return the canonical name of a tag if the synonym is normalized', () => { - expect(testDictionary.normalise(TAG_SYNONYM)).toBe(TAG_DEF.title); + testDictionary.normalise('foo'); + + expect(normalizeSpy).toHaveBeenCalled(); }); }); describe('normalize', () => { - // covered by tests for `normalise` + it('returns the title if it is not a synonym', () => { + expect(testDictionary.normalize('FooBar')).toBe('foobar'); + expect(testDictionary.normalize(TAG_TITLE)).toBe(TAG_DEF.title); + }); + + it('returns the canonical name if the synonym is normalized', () => { + expect(testDictionary.normalize(TAG_SYNONYM)).toBe(TAG_DEF.title); + }); }); describe('Dictionary', () => { - it('should be a constructor', () => { + it('is a constructor', () => { function newDictionary() { return new dictionary.Dictionary(); } diff --git a/packages/jsdoc/test/specs/jsdoc/tag/dictionary/definitions.js b/packages/jsdoc/test/specs/jsdoc/tag/dictionary/definitions.js index cad8792e..fc1ec52d 100644 --- a/packages/jsdoc/test/specs/jsdoc/tag/dictionary/definitions.js +++ b/packages/jsdoc/test/specs/jsdoc/tag/dictionary/definitions.js @@ -1,124 +1,35 @@ describe('jsdoc/tag/dictionary/definitions', () => { - const env = require('jsdoc/env'); const definitions = require('jsdoc/tag/dictionary/definitions'); - const Dictionary = require('jsdoc/tag/dictionary').Dictionary; - it('should exist', () => { - expect(definitions).toBeObject(); - }); - - it('should export a baseTags object', () => { + it('has a baseTags object', () => { expect(definitions.baseTags).toBeObject(); }); - it('should export a closureTags object', () => { + it('has a closureTags object', () => { expect(definitions.closureTags).toBeObject(); }); - it('should export a defineTags method', () => { - expect(definitions.defineTags).toBeFunction(); + it('has an internalTags object', () => { + expect(definitions.internalTags).toBeObject(); }); - it('should export a jsdocTags object', () => { + it('has a jsdocTags object', () => { expect(definitions.jsdocTags).toBeObject(); }); describe('baseTags', () => { - // nothing to test except which tags are on the list, which would duplicate the code + // Nothing to test except which tags are on the list, which would duplicate the code. }); describe('closureTags', () => { - // nothing to test except which tags are on the list, which would duplicate the code + // Nothing to test except which tags are on the list, which would duplicate the code. }); - describe('defineTags', () => { - const CLOSURE_TAGNAME = 'final'; - const dictionaryConfig = env.conf.tags.dictionaries.slice(0); - const JSDOC_TAGNAME = 'abstract'; - let tagDict; - - beforeEach(() => { - env.conf.tags.dictionaries = []; - tagDict = new Dictionary(); - }); - - afterEach(() => { - env.conf.tags.dictionaries = dictionaryConfig.slice(0); - }); - - it('should log an error if `env.conf.tags.dictionaries` is undefined', () => { - function defineTags() { - env.conf.tags.dictionaries = undefined; - definitions.defineTags(tagDict); - } - - expect(jsdoc.didLog(defineTags, 'error')).toBeTrue(); - }); - - it('should log an error if an unknown dictionary is requested', () => { - function defineTags() { - env.conf.tags.dictionaries = ['jsmarmoset']; - definitions.defineTags(tagDict); - } - - expect(jsdoc.didLog(defineTags, 'error')).toBeTrue(); - }); - - it('should add both JSDoc and Closure tags by default', () => { - env.conf.tags.dictionaries = dictionaryConfig.slice(0); - definitions.defineTags(tagDict); - - expect(tagDict.lookUp(JSDOC_TAGNAME)).toBeObject(); - expect(tagDict.lookUp(CLOSURE_TAGNAME)).toBeObject(); - }); - - it('should add only the JSDoc tags if requested', () => { - env.conf.tags.dictionaries = ['jsdoc']; - definitions.defineTags(tagDict); - - expect(tagDict.lookUp(JSDOC_TAGNAME)).toBeObject(); - expect(tagDict.lookUp(CLOSURE_TAGNAME)).toBeFalse(); - }); - - it('should add only the Closure tags if requested', () => { - env.conf.tags.dictionaries = ['closure']; - definitions.defineTags(tagDict); - - expect(tagDict.lookUp(JSDOC_TAGNAME)).toBeFalse(); - expect(tagDict.lookUp(CLOSURE_TAGNAME)).toBeObject(); - }); - - it('should prefer tagdefs from the first dictionary on the list', () => { - env.conf.tags.dictionaries = ['closure', 'jsdoc']; - definitions.defineTags(tagDict); - - expect(tagDict.lookUp('deprecated').synonyms).not.toBeDefined(); - }); - - it('should add tag synonyms', () => { - env.conf.tags.dictionaries = ['jsdoc']; - definitions.defineTags(tagDict); - - expect(tagDict.lookUp('extends')).toBeObject(); - expect(tagDict.normalize('extends')).toBe('augments'); - }); - - it('should ignore the config settings if tagdefs are passed in', () => { - const tagDefs = { - foo: { - mustHaveValue: false - } - }; - - env.conf.tags.dictionaries = ['jsdoc']; - definitions.defineTags(tagDict, tagDefs); - - expect(tagDict.lookUp('foo')).toBeObject(); - expect(tagDict.lookUp('abstract')).toBeFalse(); - }); + describe('internalTags', () => { + // Nothing to test except which tags are on the list, which would duplicate the code. }); describe('jsdocTags', () => { - // nothing to test except which tags are on the list, which would duplicate the code + // Nothing to test except which tags are on the list, which would duplicate the code. }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/util/templateHelper.js b/packages/jsdoc/test/specs/jsdoc/util/templateHelper.js index 98094518..9dad4af3 100644 --- a/packages/jsdoc/test/specs/jsdoc/util/templateHelper.js +++ b/packages/jsdoc/test/specs/jsdoc/util/templateHelper.js @@ -3,7 +3,6 @@ const hasOwnProp = Object.prototype.hasOwnProperty; describe("jsdoc/util/templateHelper", () => { const _ = require('lodash'); - const definitions = require('jsdoc/tag/dictionary/definitions'); const dictionary = require('jsdoc/tag/dictionary'); const doclet = require('jsdoc/doclet'); const env = require('jsdoc/env'); @@ -201,7 +200,6 @@ describe("jsdoc/util/templateHelper", () => { dict.defineTag('anaphylaxis', { isNamespace: true }); - definitions.defineTags(dict); doclet._replaceDictionary(dict); filename = helper.getUniqueFilename('anaphylaxis:peanut');