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.
This commit is contained in:
Jeff Williams 2021-09-18 12:07:10 -07:00
parent 8a0a078f94
commit 3025520e15
7 changed files with 298 additions and 273 deletions

View File

@ -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) {

View File

@ -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;

View File

@ -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
};

View File

@ -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));
}
};

View File

@ -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();
}

View File

@ -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.
});
});

View File

@ -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');