the common prefix for one file is the file's dirname (#553)

This commit is contained in:
Jeff Williams 2013-12-26 21:19:37 -08:00
parent 22d4ce4eed
commit 6d83ffd060
6 changed files with 119 additions and 21 deletions

View File

@ -42,6 +42,7 @@ function prefixReducer(previousPath, current) {
*
* For example, assuming that the current working directory is `/Users/jsdoc`:
*
* + For the single path `foo/bar/baz/qux.js`, the common prefix is `foo/bar/baz/`.
* + For paths `foo/bar/baz/qux.js`, `foo/bar/baz/quux.js`, and `foo/bar/baz.js`, the common prefix
* is `/Users/jsdoc/foo/bar/`.
* + For paths `../jsdoc/foo/bar/baz/qux/quux/test.js`, `/Users/jsdoc/foo/bar/bazzy.js`, and
@ -53,18 +54,34 @@ function prefixReducer(previousPath, current) {
* @return {string} The common prefix, or an empty string if there is no common prefix.
*/
exports.commonPrefix = function(paths) {
var common;
var segments;
var prefix = '';
paths = paths || [];
common = paths.reduce(prefixReducer, undefined) || [];
// if there's anything left (other than a placeholder for a leading slash), add a placeholder
// for a trailing slash
if ( common.length && (common.length > 1 || common[0] !== '') ) {
common.push('');
// if there's only one path, its resolved dirname (plus a trailing slash) is the common prefix
if (paths.length === 1) {
prefix = path.resolve(global.env.pwd, paths[0]);
if ( path.extname(prefix) ) {
prefix = path.dirname(prefix);
}
prefix += path.sep;
}
else {
segments = paths.reduce(prefixReducer, undefined) || [];
// if there's anything left (other than a placeholder for a leading slash), add a
// placeholder for a trailing slash
if ( segments.length && (segments.length > 1 || segments[0] !== '') ) {
segments.push('');
}
prefix = segments.join(path.sep);
}
return common.join(path.sep);
return prefix;
};
/**

View File

@ -14,9 +14,13 @@ var Syntax = require('jsdoc/src/syntax').Syntax;
function filepathMinusPrefix(filepath) {
var sourceFiles = env.sourceFiles || [];
var commonPrefix = path.commonPrefix( sourceFiles.concat(env.opts._ || []) );
// always use forward slashes
var result = (filepath + path.sep).replace(commonPrefix, '')
.replace(/\\/g, '/');
var result = '';
if (filepath) {
// always use forward slashes
result = (filepath + path.sep).replace(commonPrefix, '')
.replace(/\\/g, '/');
}
if (result.length > 0 && result[result.length - 1] !== '/') {
result += '/';

View File

@ -102,12 +102,35 @@ function normalizeArray(parts, allowAboveRoot) {
return parts;
}
exports.extname = function(path) {
return splitPath(path)[3];
};
if (isWindows) {
// Regex to split a windows path into three parts: [*, device, slash,
// tail] windows-only
var splitDeviceRe =
/^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?([\\\/])?([\s\S]*?)$/;
// Regex to split the tail part of the above into [*, dir, basename, ext]
var splitTailRe =
/^([\s\S]*?)((?:\.{1,2}|[^\\\/]+?|)(\.[^.\/\\]*|))(?:[\\\/]*)$/;
// Function to split a filename into [root, dir, basename, ext]
// windows version
var splitPath = function(filename) {
// Separate device+slash from tail
var result = splitDeviceRe.exec(filename),
device = (result[1] || '') + (result[2] || ''),
tail = result[3] || '';
// Split the tail into dir, basename and extension
var result2 = splitTailRe.exec(tail),
dir = result2[1],
basename = result2[2],
ext = result2[3];
return [device, dir, basename, ext];
};
// path.resolve([from ...], to)
// windows version
exports.resolve = function() {
@ -292,6 +315,14 @@ if (isWindows) {
return outputParts.join('\\');
};
} else {
// Split a filename into [root, dir, basename, ext], unix version
// 'root' is just a slash, or nothing.
var splitPathRe =
/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
var splitPath = function(filename) {
return splitPathRe.exec(filename).slice(1);
};
// path.resolve([from ...], to)
// posix version
exports.resolve = function() {

View File

@ -6,22 +6,31 @@ describe("module names", function() {
var doclets;
var pwd = env.pwd;
var srcParser = null;
var sourceFiles = env.sourceFiles.slice(0);
var sourcePaths = env.opts._.slice(0);
beforeEach(function() {
env.opts._ = [path.normalize(env.dirname + '/test/fixtures/modules/data/')];
env.opts._ = [path.normalize(env.pwd + '/test/fixtures/modules/data/')];
env.pwd = env.dirname;
env.sourceFiles = [];
srcParser = jasmine.createParser();
require('jsdoc/src/handlers').attachTo(srcParser);
});
afterEach(function() {
env.opts._ = sourcePaths;
env.pwd = pwd;
env.sourceFiles = sourceFiles;
});
it("should create a name from the file path when no documented module name exists", function() {
var filename = 'test/fixtures/modules/data/mod-1.js';
env.sourceFiles.push(filename);
doclets = srcParser.parse(
path.normalize(env.dirname + '/test/fixtures/modules/data/mod-1.js')
path.normalize( path.join(env.pwd, filename) )
);
expect(doclets.length).toBeGreaterThan(1);
expect(doclets[0].longname).toEqual('module:mod-1');
@ -33,8 +42,6 @@ describe("module names", function() {
var Doclet = require('jsdoc/doclet').Doclet;
var doclet;
// setup
var sourceFiles = env.sourceFiles.slice(0);
env.sourceFiles = [
'C:\\Users\\Jane Smith\\myproject\\index.js',
'C:\\Users\\Jane Smith\\myproject\\lib\\mymodule.js'
@ -47,16 +54,17 @@ describe("module names", function() {
});
expect(doclet.name).toBe('lib/mymodule');
// teardown
env.sourceFiles = sourceFiles;
});
}
it("should use the documented module name if available", function() {
var filename = 'test/fixtures/modules/data/mod-2.js';
env.sourceFiles.push(filename);
doclets = srcParser.parse(
path.normalize(env.dirname + '/test/fixtures/modules/data/mod-2.js')
path.normalize( path.join(env.pwd, filename) )
);
expect(doclets.length).toBeGreaterThan(1);
expect(doclets[0].longname).toEqual('module:my/module/name');
});

View File

@ -46,6 +46,14 @@ describe('jsdoc/path', function() {
global.env.pwd = oldPwd;
});
it('finds the correct prefix for a single relative path', function() {
var paths = [path.join('foo', 'bar', 'baz', 'qux.js')];
// we expect a trailing slash
var expected = cwd.concat('foo', 'bar', 'baz', '').join(path.sep);
expect( path.commonPrefix(paths) ).toBe(expected);
});
it('finds the correct prefix for a group of relative paths', function() {
var paths = [
path.join('foo', 'bar', 'baz', 'qux.js'),
@ -58,6 +66,14 @@ describe('jsdoc/path', function() {
expect( path.commonPrefix(paths) ).toEqual(expected);
});
it('finds the correct prefix for a single absolute path', function() {
var paths = [cwd.concat('foo', 'bar', 'baz', 'qux.js').join(path.sep)];
// we expect a trailing slash
var expected = cwd.concat('foo', 'bar', 'baz', '').join(path.sep);
expect( path.commonPrefix(paths) ).toBe(expected);
});
it('finds the correct prefix for a group of absolute paths', function() {
var paths = [
cwd.concat('foo', 'bar', 'baz', 'qux.js').join(path.sep),
@ -83,6 +99,12 @@ describe('jsdoc/path', function() {
expect( path.commonPrefix(paths) ).toEqual(expected);
});
it('returns an empty string when the paths array is empty', function() {
var paths = [];
expect( path.commonPrefix(paths) ).toBe('');
});
// skip on Windows, since the paths share a drive letter at the start
if (!isWindows) {
it('returns an empty string when there is no common prefix', function() {

View File

@ -7,26 +7,42 @@ describe("@overview tag", function() {
var doclets;
var pwd = env.pwd;
var srcParser = null;
var sourceFiles = env.sourceFiles.slice(0);
var sourcePaths = env.opts._.slice(0);
beforeEach(function() {
env.opts._ = [path.normalize(env.dirname + '/test/fixtures/')];
env.opts._ = [path.normalize(env.pwd + '/test/fixtures/')];
env.pwd = env.dirname;
env.sourceFiles = [];
srcParser = jasmine.createParser();
require('jsdoc/src/handlers').attachTo(srcParser);
});
afterEach(function() {
env.opts._ = sourcePaths;
env.pwd = pwd;
env.sourceFiles = sourceFiles;
});
it('When a file overview tag appears in a doclet, the name of the doclet should contain the path to the file.', function() {
doclets = srcParser.parse( path.normalize(env.dirname + '/test/fixtures/file.js') );
var filename = 'test/fixtures/file.js';
env.sourceFiles.push(filename);
doclets = srcParser.parse(
path.normalize( path.join(env.pwd, filename) )
);
expect(doclets[0].name).toMatch(/^file\.js$/);
});
it("The name and longname should be equal", function() {
doclets = srcParser.parse( path.normalize(env.dirname + '/test/fixtures/file.js') );
var filename = 'test/fixtures/file.js';
env.sourceFiles.push(filename);
doclets = srcParser.parse(
path.normalize( path.join(env.pwd, filename) )
);
expect(doclets[0].name).toBe(doclets[0].longname);
});
});