This commit is contained in:
Jeff Williams 2017-07-11 15:48:49 -07:00
parent f17395302f
commit 7f8b997d5c
2 changed files with 38 additions and 35 deletions

View File

@ -86,8 +86,8 @@ exports.commonPrefix = function(paths) {
* Retrieve the fully qualified path to the requested resource. * Retrieve the fully qualified path to the requested resource.
* *
* Plugins and templates will be found somewhat similar to how `require()` works, except that the * Plugins and templates will be found somewhat similar to how `require()` works, except that the
* directory in which the JSDoc configuration file is will be considered, too, the JSDoc package * directory in which the JSDoc configuration file is will be considered, too; the JSDoc package's
* directory will be considered as a fallback, and a globally installed resource won't be found * directory will be considered as a fallback; and a globally installed resource won't be found
* unless it comes with JSDoc. * unless it comes with JSDoc.
* *
* If the resource path is specified as a path relative to module or package (starting with `.` or * If the resource path is specified as a path relative to module or package (starting with `.` or
@ -106,19 +106,20 @@ exports.commonPrefix = function(paths) {
* Includes the filename if one was provided. * Includes the filename if one was provided.
*/ */
exports.getResourcePath = function(filepath, filename) { exports.getResourcePath = function(filepath, filename) {
var pathElems;
var result = null; var result = null;
var searchDirs = []; var searchDirs = [];
function pathExists(_path) { function directoryExists(dir) {
var stats;
try { try {
fs.readdirSync(_path); stats = fs.statSync(dir);
return stats.isDirectory();
} }
catch (e) { catch (e) {
return false; return false;
} }
return true;
} }
// resources that are installed modules may not have been specified with a filepath // resources that are installed modules may not have been specified with a filepath
@ -126,18 +127,16 @@ exports.getResourcePath = function(filepath, filename) {
filepath = filename; filepath = filename;
filename = undefined; filename = undefined;
} }
pathElems = filepath.split(path.sep);
// Special case `node_modules/foo`, to accommodate this legacy workaround advertised by // Special case `node_modules/foo`, to accommodate this legacy workaround advertised by
// third-party plugin and template authors // third-party plugin and template authors.
if (pathElems[0] === 'node_modules') { if ( /^node_modules\//.test(filepath) ) {
pathElems.unshift('.'); filepath = path.join('.', filepath);
filepath = pathElems.join(path.sep);
} }
// search in different sets of directories depending on whether filepath is expressly relative // search in different sets of directories depending on whether filepath is expressly relative
// to "current" directory or not // to "current" directory or not
searchDirs = pathElems[0].indexOf('.') === 0 ? searchDirs = /^\./.test(filepath) ?
// look first in "current" (where JSDoc was executed), then in directory of config, and // look first in "current" (where JSDoc was executed), then in directory of config, and
// _only then_ in JSDoc's directory // _only then_ in JSDoc's directory
[env.pwd, path.dirname(env.opts.configure || ''), env.dirname] : [env.pwd, path.dirname(env.opts.configure || ''), env.dirname] :
@ -147,14 +146,17 @@ exports.getResourcePath = function(filepath, filename) {
path.join(path.dirname(env.opts.configure || ''), 'node_modules'), path.join(path.dirname(env.opts.configure || ''), 'node_modules'),
env.dirname]; env.dirname];
// absolute paths are normalized by path.resolve on the first pass searchDirs.some(function(dir) {
searchDirs.forEach(function(_path) { if (dir) {
if (!result && _path) { dir = path.resolve(dir, filepath);
_path = path.resolve(_path, filepath); if ( directoryExists(dir) ) {
if ( pathExists(_path) ) { result = dir;
result = _path;
return true;
} }
} }
return false;
}); });
if (result) { if (result) {

View File

@ -146,56 +146,57 @@ describe('jsdoc/path', function() {
it('resolves package-relative path that exists', function() { it('resolves package-relative path that exists', function() {
var resolved = path.getResourcePath('plugins'); var resolved = path.getResourcePath('plugins');
expect( resolved ).not.toBeNull(); expect(resolved).not.toBeNull();
expect( path.isAbsolute(resolved) ).toBe(true); expect( path.isAbsolute(resolved) ).toBe(true);
}); });
it('fails to resolve package-relative path that exists in ./', function() { it('fails to resolve package-relative path that exists in ./', function() {
var resolved = path.getResourcePath('util'); var resolved = path.getResourcePath('util');
expect( resolved ).toBeNull(); expect(resolved).toBeNull();
}); });
it('resolves relative to ./ path that exists', function() { it('resolves relative to ./ path that exists', function() {
// `path.join` discards the `.`, so we join with `path.sep` instead
var p = ['.', 'util'].join(path.sep); var p = ['.', 'util'].join(path.sep);
var resolved = path.getResourcePath(p); var resolved = path.getResourcePath(p);
expect( resolved ).not.toBeNull(); expect(resolved).not.toBeNull();
expect( path.isAbsolute(resolved) ).toBe(true); expect( path.isAbsolute(resolved) ).toBe(true);
}); });
it('resolves relative to ../ path that exists', function() { it('resolves relative to ../ path that exists', function() {
var p = ['..', 'jsdoc', 'util'].join(path.sep); var p = path.join('..', 'jsdoc', 'util');
var resolved = path.getResourcePath(p); var resolved = path.getResourcePath(p);
expect( resolved ).not.toBeNull(); expect(resolved).not.toBeNull();
expect( path.isAbsolute(resolved) ).toBe(true); expect( path.isAbsolute(resolved) ).toBe(true);
}); });
it('resolves relative to ../ path that exists in ../ and package', function() { it('resolves relative to ../ path that exists in ../ and package', function() {
var prel = ['..', 'plugins'].join(path.sep); var prel = path.join('..', 'plugins');
var pabs = 'plugins'; var pabs = 'plugins';
var resolved = path.getResourcePath(prel); var resolved = path.getResourcePath(prel);
expect( resolved ).not.toBeNull(); expect(resolved).not.toBeNull();
expect( path.getResourcePath(pabs) ).not.toBeNull(); expect( path.getResourcePath(pabs) ).not.toBeNull();
expect( path.isAbsolute(resolved) ).toBe(true); expect( path.isAbsolute(resolved) ).toBe(true);
expect( path.getResourcePath(pabs) ).not.toBe( resolved ); expect( path.getResourcePath(pabs) ).not.toBe(resolved);
}); });
it('resolves relative to . path that exists in package', function() { it('resolves relative to . path that exists in package', function() {
var p = ['.', 'plugins'].join(path.sep); var p = path.join('.', 'plugins');
var resolved = path.getResourcePath(p); var resolved = path.getResourcePath(p);
expect( resolved ).not.toBeNull(); expect(resolved).not.toBeNull();
expect( path.isAbsolute(resolved) ).toBe(true); expect( path.isAbsolute(resolved) ).toBe(true);
}); });
it('resolves path using node_modules/', function() { it('resolves path using node_modules/', function() {
var p = ['node_modules', 'marked'].join(path.sep); var p = path.join('node_modules', 'marked');
var resolved = path.getResourcePath( path.dirname(p), path.basename(p) ); var resolved = path.getResourcePath( path.dirname(p), path.basename(p) );
expect( resolved ).not.toBeNull(); expect(resolved).not.toBeNull();
expect( path.isAbsolute(resolved) ).toBe(true); expect( path.isAbsolute(resolved) ).toBe(true);
}); });
@ -203,16 +204,16 @@ describe('jsdoc/path', function() {
var p = 'marked'; var p = 'marked';
var resolved = path.getResourcePath(undefined, p); var resolved = path.getResourcePath(undefined, p);
expect( resolved ).not.toBeNull(); expect(resolved).not.toBeNull();
expect( path.isAbsolute(resolved) ).toBe(true); expect( path.isAbsolute(resolved) ).toBe(true);
}); });
it('leaves an absolute path as is', function() { it('leaves an absolute path as is', function() {
var p = path.resolve([env.dirname, 'anything'].join(path.sep)); var p = path.resolve( path.join(env.dirname, 'anything') );
var resolved = path.getResourcePath(path.dirname(p), 'anything'); var resolved = path.getResourcePath(path.dirname(p), 'anything');
expect( resolved ).not.toBeNull(); expect(resolved).not.toBeNull();
expect( p ).toEqual( resolved ); expect(p).toBe(resolved);
}); });
}); });
}); });