add longnamesToTree method

This commit is contained in:
Jeff Williams 2014-07-03 13:53:46 -07:00
parent dcca9a4714
commit cae3cce8c1
3 changed files with 109 additions and 42 deletions

View File

@ -65,9 +65,10 @@ var scopeToPunc = exports.scopeToPunc = {
var puncToScope = exports.puncToScope = _.invert(scopeToPunc);
var DEFAULT_SCOPE = SCOPE.NAMES.STATIC;
var REGEXP_SCOPE_PUNC = '([' + _.values(SCOPE.PUNC) + '])';
var REGEXP_LEADING_SCOPE = new RegExp('^' + REGEXP_SCOPE_PUNC);
var REGEXP_TRAILING_SCOPE = new RegExp(REGEXP_SCOPE_PUNC + '$');
var SCOPE_PUNC = _.values(SCOPE.PUNC);
var REGEXP_SCOPE_PUNC = '[' + SCOPE_PUNC.join() + ']';
var REGEXP_LEADING_SCOPE = new RegExp('^(' + REGEXP_SCOPE_PUNC + ')');
var REGEXP_TRAILING_SCOPE = new RegExp('(' + REGEXP_SCOPE_PUNC + ')$');
function nameIsLongname(name, memberof) {
var regexp = new RegExp('^' + memberof + REGEXP_SCOPE_PUNC);
@ -206,18 +207,19 @@ exports.applyNamespace = function(longname, ns) {
return longname;
};
/**
Given a longname like "a.b#c(2)", slice it up into an object
containing the memberof, the scope, the name, and variation.
@param {string} longname
@param {string} forcedMemberof
@returns {object} Representing the properties of the given name.
*/
exports.shorten = function(longname, forcedMemberof) {
// quoted strings in a longname are atomic, convert to tokens
var atoms = [], token;
// TODO: docs
function shorten(longname, sliceChars, forcedMemberof) {
var i;
var memberof = '';
var name = '';
var parts;
var partsRegExp;
var scope = '';
var token;
var tokens = [];
var variation;
// handle quoted names like foo["bar"] or foo['bar']
// quoted strings in a longname are atomic, so we convert them to tokens
longname = longname.replace(/(\[?["'].+?["']\]?)/g, function($) {
var dot = '';
if ( /^\[/.test($) ) {
@ -225,34 +227,31 @@ exports.shorten = function(longname, forcedMemberof) {
$ = $.replace( /^\[/g, '' ).replace( /\]$/g, '' );
}
token = '@{' + atoms.length + '}@';
atoms.push($);
token = '@{' + tokens.length + '}@';
tokens.push($);
return dot + token; // foo["bar"] => foo.@{1}@
});
var name = '',
scope = '', // ., ~, or #
memberof = '',
parts,
variation;
longname = prototypeToPunc(longname);
if (typeof forcedMemberof !== 'undefined') {
if (forcedMemberof !== undefined) {
partsRegExp = new RegExp('^(.*?)([' + sliceChars.join() + ']?)$');
name = longname.substr(forcedMemberof.length);
parts = forcedMemberof.match(/^(.*?)([#.~]?)$/);
parts = forcedMemberof.match(partsRegExp);
if (parts[1]) { memberof = parts[1] || forcedMemberof; }
if (parts[2]) { scope = parts[2]; }
if (parts[1]) {
memberof = parts[1] || forcedMemberof;
}
else {
parts = longname ?
(longname.match( /^(:?(.+)([#.~]))?(.+?)$/ ) || []).reverse() :
[''];
name = parts[0] || ''; // ensure name is always initialised to avoid error being thrown when calling replace on undefined [gh-24]
scope = parts[1] || ''; // ., ~, or #
if (parts[2]) {
scope = parts[2];
}
}
else if (longname) {
parts = (longname.match(new RegExp('^(:?(.+)([' + sliceChars.join() + ']))?(.+?)$')) || [])
.reverse();
name = parts[0] || '';
scope = parts[1] || '';
memberof = parts[2] || '';
}
@ -262,17 +261,71 @@ exports.shorten = function(longname, forcedMemberof) {
variation = RegExp.$2;
}
//// restore quoted strings back again
var i = atoms.length;
// restore quoted strings
i = tokens.length;
while (i--) {
longname = longname.replace('@{' + i + '}@', atoms[i]);
memberof = memberof.replace('@{' + i + '}@', atoms[i]);
scope = scope.replace('@{' + i + '}@', atoms[i]);
name = name.replace('@{' + i + '}@', atoms[i]);
longname = longname.replace('@{' + i + '}@', tokens[i]);
memberof = memberof.replace('@{' + i + '}@', tokens[i]);
scope = scope.replace('@{' + i + '}@', tokens[i]);
name = name.replace('@{' + i + '}@', tokens[i]);
}
////
return {longname: longname, memberof: memberof, scope: scope, name: name, variation: variation};
}
/**
Given a longname like "a.b#c(2)", slice it up into an object
containing the memberof, the scope, the name, and variation.
@param {string} longname
@param {string} forcedMemberof
@returns {object} Representing the properties of the given name.
*/
exports.shorten = function(longname, forcedMemberof) {
return shorten(longname, SCOPE_PUNC, forcedMemberof);
};
function splitLongname(longname) {
var chunks = [];
var currentNameInfo;
var nameInfo = {};
var previousName = longname;
var splitters = SCOPE_PUNC.concat('/');
do {
currentNameInfo = nameInfo[previousName] = shorten(previousName, splitters);
previousName = currentNameInfo.memberof;
chunks.push(currentNameInfo.scope + currentNameInfo.name);
} while (previousName);
return {
chunks: chunks.reverse(),
nameInfo: nameInfo
};
}
// TODO: docs
exports.longnamesToTree = function longnamesToTree(longnames, doclets) {
var tree = {};
longnames.forEach(function(longname) {
var processed = splitLongname(longname);
var nameInfo = processed.nameInfo;
var chunk;
var currentLongname = '';
var currentNavItem = tree;
processed.chunks.forEach(function(chunk) {
currentLongname += chunk;
currentNavItem[chunk] = currentNavItem[chunk] || nameInfo[currentLongname];
currentNavItem[chunk].doclet = doclets ? doclets[currentLongname] : null;
currentNavItem[chunk].children = currentNavItem[chunk].children || {};
currentNavItem = currentNavItem[chunk].children;
});
});
return tree;
};
/**

View File

@ -6,12 +6,14 @@
var catharsis = require('catharsis');
var dictionary = require('jsdoc/tag/dictionary');
var name = require('jsdoc/name');
var util = require('util');
var hasOwnProp = Object.prototype.hasOwnProperty;
var NAMESPACES = require('jsdoc/name').NAMESPACES;
var files = {};
var ids = {};
// each container gets its own html file
var containers = ['class', 'module', 'external', 'namespace', 'mixin'];
@ -760,3 +762,6 @@ exports.createLink = function(doclet) {
return url;
};
// TODO: docs
exports.longnamesToTree = name.longnamesToTree;

View File

@ -1,4 +1,4 @@
/*global afterEach, beforeEach, describe, expect, env, it, jasmine, spyOn */
/*global afterEach, beforeEach, describe, expect, env, it, jasmine, spyOn, xdescribe */
/*eslint quotes:0 */
'use strict';
@ -133,6 +133,11 @@ describe("jsdoc/util/templateHelper", function() {
expect(typeof helper.createLink).toBe("function");
});
it('should export a "longnamesToTree" function', function() {
expect(helper.longnamesToTree).toBeDefined();
expect(typeof helper.longnamesToTree).toBe('function');
});
describe("setTutorials", function() {
// used in tutorialToUrl, toTutorial.
it("setting tutorials to null causes all tutorial lookups to fail", function() {
@ -412,7 +417,7 @@ describe("jsdoc/util/templateHelper", function() {
{kind: 'class', memberof: 'SomeNamespace'} // not global
];
var externals = [
{kind: 'external'}
{kind: 'external', name: 'foo'}
];
var events = [
{kind: 'event'}
@ -1425,4 +1430,8 @@ describe("jsdoc/util/templateHelper", function() {
expect(out).toBe(helper.htmlsafe(str));
});
});
xdescribe('longnamesToTree', function() {
// TODO
});
});