provide a setter for doclet scope (#574)

We previously set the doclet's scope by adding a
`@scope` tag, which, in turn, was used to update
the scope. Since this tag isn't defined or used in
any other context, it could cause "not a known
tag" errors.
This commit is contained in:
Jeff Williams 2014-02-16 07:44:28 -08:00
parent f4a38b442f
commit 3ae23b8b21
5 changed files with 113 additions and 7 deletions

View File

@ -24,6 +24,7 @@ var jsdoc = {
}
};
var path = require('jsdoc/path');
var util = require('util');
// Longname used for doclets whose actual longname cannot be identified.
@ -46,10 +47,6 @@ function applyTag(doclet, tag) {
if (tag.title === 'description') {
doclet.description = tag.value;
}
if (tag.title === 'scope') {
doclet.scope = tag.value;
}
}
// use the meta info about the source code to guess what the doclet kind should be
@ -250,6 +247,50 @@ Doclet.prototype.setLongname = function(name) {
}
};
/**
* Get the full path to the source file that is associated with a doclet.
*
* @private
* @param {module:jsdoc/doclet.Doclet} The doclet to check for a filepath.
* @return {string} The path to the doclet's source file, or an empty string if the path is not
* available.
*/
function getFilepath(doclet) {
if (!doclet || !doclet.meta || !doclet.meta.filename) {
return '';
}
return path.join(doclet.meta.path || '', doclet.meta.filename);
}
/**
* Set the doclet's `scope` property. Must correspond to a scope name that is defined in
* {@link module:jsdoc/name.SCOPE_NAMES}.
*
* @param {module:jsdoc/name.SCOPE_NAMES} scope - The scope for the doclet relative to the symbol's
* parent.
* @throws {Error} If the scope name is not recognized.
*/
Doclet.prototype.setScope = function(scope) {
var errorMessage;
var filepath;
var scopeNames = Object.keys(jsdoc.name.SCOPE_NAMES);
if (scopeNames.indexOf(scope) === -1) {
filepath = getFilepath(this);
errorMessage = util.format('The scope name "%s" is not recognized. Use one of the names ' +
'defined in module:jsdoc/name.SCOPE_NAMES.', scope);
if (filepath) {
errorMessage += util.format(' (Source file: %s)', filepath);
}
throw new Error(errorMessage);
}
this.scope = scope;
};
/**
* Add a symbol to this doclet's `borrowed` array.
*

View File

@ -14,6 +14,12 @@ var jsdoc = {
};
// Scope identifiers.
var SCOPE_NAMES = exports.SCOPE_NAMES = {
global: 'global',
inner: 'inner',
instance: 'instance',
'static': 'static'
};
var INNER = exports.INNER = '~';
var INSTANCE = exports.INSTANCE = '#';
var STATIC = exports.STATIC = '.';
@ -26,7 +32,7 @@ var puncToScope = exports.puncToScope = _.invert(scopeToPunc);
var MODULE_PREFIX = exports.MODULE_PREFIX = 'module:';
var DEFAULT_SCOPE = 'static';
var DEFAULT_SCOPE = SCOPE_NAMES.static;
/**
Resolves the longname, memberof, variation and name values of the given doclet.

View File

@ -8,6 +8,7 @@
*/
'use strict';
var logger = require('jsdoc/util/logger');
var path = require('jsdoc/path');
var Syntax = require('jsdoc/src/syntax').Syntax;
@ -35,7 +36,12 @@ function setDocletKindToTitle(doclet, tag) {
}
function setDocletScopeToTitle(doclet, tag) {
doclet.addTag( 'scope', tag.title );
try {
doclet.setScope(tag.title);
}
catch(e) {
logger.error(e.message);
}
}
function setDocletNameToValue(doclet, tag) {

View File

@ -1,7 +1,8 @@
/*global describe: true, env: true, expect: true, it: true, jasmine: true */
describe("jsdoc/doclet", function() {
// TODO: more tests
var Doclet = require('jsdoc/doclet').Doclet;
var docSet = jasmine.getDocSetFromFile('test/fixtures/doclet.js'),
test1 = docSet.getByLongname('test1')[0],
test2 = docSet.getByLongname('test2')[0];
@ -13,4 +14,26 @@ describe("jsdoc/doclet", function() {
expect(test2.description.indexOf(expectStrong)).toBeGreaterThan(-1);
expect(test2.description.indexOf(expectList)).toBeGreaterThan(-1);
});
describe('setScope', function() {
it('should accept the correct scope names', function() {
function setScope(scopeName) {
var doclet = new Doclet('/** Huzzah, a doclet! */', {});
doclet.setScope(scopeName);
}
Object.keys(require('jsdoc/name').SCOPE_NAMES).forEach(function(scopeName) {
expect( setScope.bind(null, scopeName) ).not.toThrow();
});
});
it('should throw an error for invalid scope names', function() {
function setScope() {
var doclet = new Doclet('/** Woe betide this doclet. */', {});
doclet.setScope('fiddlesticks');
}
expect(setScope).toThrow();
});
});
});

View File

@ -18,6 +18,12 @@ describe("jsdoc/name", function() {
expect(typeof jsdoc.name.applyNamespace).toEqual("function");
});
// TODO: add tests for other exported constants
it('should export a SCOPE_NAMES enum', function() {
expect(jsdoc.name.SCOPE_NAMES).toBeDefined();
expect(typeof jsdoc.name.SCOPE_NAMES).toBe('object');
});
it("should export an 'shorten' function", function() {
expect(jsdoc.name.shorten).toBeDefined();
expect(typeof jsdoc.name.shorten).toEqual("function");
@ -28,6 +34,30 @@ describe("jsdoc/name", function() {
expect(typeof jsdoc.name.splitName).toEqual("function");
});
describe('SCOPE_NAMES', function() {
var SCOPE_NAMES = jsdoc.name.SCOPE_NAMES;
it('should have a "global" property', function() {
expect(SCOPE_NAMES.global).toBeDefined();
expect(typeof SCOPE_NAMES.global).toBe('string');
});
it('should have an "inner" property', function() {
expect(SCOPE_NAMES.inner).toBeDefined();
expect(typeof SCOPE_NAMES.inner).toBe('string');
});
it('should have an "instance" property', function() {
expect(SCOPE_NAMES.instance).toBeDefined();
expect(typeof SCOPE_NAMES.instance).toBe('string');
});
it('should have a "static" property', function() {
expect(SCOPE_NAMES.static).toBeDefined();
expect(typeof SCOPE_NAMES.static).toBe('string');
});
});
describe ("shorten", function() {
it('should break up a longname into the correct memberof, name and scope parts', function() {
var startName = 'lib.Panel#open',