improvements to interface and implements tags

- Change doclet property names
- Populate the list of property implementations in augment.js, not in the template
- Tone down the presentation of both tags in the default template
- Other related cleanup
This commit is contained in:
Jeff Williams 2014-08-11 15:58:19 -07:00
parent 277d712f3e
commit 2f87fb11dc
6 changed files with 92 additions and 94 deletions

View File

@ -145,40 +145,40 @@ exports.addInherited = function(docs) {
exports.addImplemented = function(docs) { exports.addImplemented = function(docs) {
var docMap = {}; var docMap = {};
var interfaces = []; var interfaces = {};
var implemented = {}; var implemented = {};
var propertyInfo = {}; var memberInfo = {};
docs.forEach(function(doc) { docs.forEach(function(doc) {
if (!hasOwnProp.call(docMap, doc.memberof)) { var memberof = doc.memberof || doc.name;
docMap[doc.memberof] = [];
if (!hasOwnProp.call(docMap, memberof)) {
docMap[memberof] = [];
} }
docMap[doc.memberof].push(doc); docMap[memberof].push(doc);
if (doc.kind === 'interface') { if (doc.kind === 'interface') {
interfaces.push(doc); interfaces[doc.longname] = doc;
} else if (doc.implements && doc.implements.length) {
if (!hasOwnProp.call(implemented, doc.memberof)) {
implemented[doc.memberof] = [];
} }
implemented[doc.memberof].push(doc); else if (doc.implements && doc.implements.length) {
if (!hasOwnProp.call(implemented, doc.memberof)) {
implemented[memberof] = [];
}
implemented[memberof].push(doc);
} }
}); });
// create an array of interface properties/methods, plus a hash of the doclet for each one // create an dictionary of interface doclets
interfaces.forEach(function(inf) { Object.keys(interfaces).forEach(function(ifaceName) {
if (hasOwnProp.call(docMap, inf.name)) { var iface = interfaces[ifaceName];
docMap[inf.name].forEach(function(obj) { if (hasOwnProp.call(docMap, iface.name)) {
var members = propertyInfo[obj.memberof]; docMap[iface.name].forEach(function(doc) {
if (!members) { var members = memberInfo[doc.memberof];
members = propertyInfo[obj.memberof] = {
props: [],
info: {}
};
}
members.props.push(obj.name); if (!members) {
members.info[obj.name] = obj; members = memberInfo[doc.memberof] = {};
}
members[doc.name] = doc;
}); });
} }
}); });
@ -187,20 +187,46 @@ exports.addImplemented = function(docs) {
// implemented classes namespace. // implemented classes namespace.
var owner = implemented[key]; var owner = implemented[key];
owner.forEach(function(cls) { owner.forEach(function(klass) {
// class's interfaces // class's interfaces
cls.implements.forEach(function(impl) { klass.implements.forEach(function(impl) {
var implProps = propertyInfo[impl]; var interfaceMember;
var props = docMap[cls.longname] || []; var interfaceMembers = memberInfo[impl];
var member;
var members;
for (var i = 0, len = props.length; i < len; i++) { // mark the interface as being implemented by the class
var prop = props[i]; if (hasOwnProp.call(interfaces, impl)) {
interfaces[impl].implementations = interfaces[impl].implementations || [];
// mark implemented properties by checking the implProps array for each name interfaces[impl].implementations.push(klass.longname);
if (implProps && implProps.props.indexOf(prop.name) > -1) {
prop.implemented = true;
prop.implementProp = implProps.info[prop.name].longname;
} }
// if the interface has no members, skip to the next owner
if (!interfaceMembers) {
return;
}
if (!hasOwnProp.call(docMap, klass.longname)) {
docMap[klass.longname] = [];
}
members = docMap[klass.longname];
for (var i = 0, len = members.length; i < len; i++) {
member = members[i];
interfaceMember = interfaceMembers && interfaceMembers[member.name];
// if we didn't find the member name in the interface, skip to the next member
if (!interfaceMember) {
continue;
}
// mark members that implement an interface
member.implements = member.implements || [];
member.implements.push(interfaceMember.longname);
// mark interface members that the symbol implements
interfaceMember.implementations = interfaceMember.implementations || [];
interfaceMember.implementations.push(member.longname);
} }
}); });
}); });

View File

@ -334,17 +334,19 @@ var DOCLET_SCHEMA = exports.DOCLET_SCHEMA = {
type: BOOLEAN, type: BOOLEAN,
optional: true optional: true
}, },
implementations: {
type: ARRAY,
optional: true,
items: {
type: STRING
}
},
implements: { implements: {
type: ARRAY, type: ARRAY,
optional: true optional: true,
}, items: {
implemented: { type: STRING
type: BOOLEAN, }
optional: true
},
implementProp: {
type: STRING,
optional: true
}, },
inherited: { inherited: {
type: BOOLEAN, type: BOOLEAN,

View File

@ -195,8 +195,8 @@ h6
} }
.details { margin-top: 14px; border-left: 2px solid #DDD; } .details { margin-top: 14px; border-left: 2px solid #DDD; }
.details dt { width:100px; float:left; padding-left: 10px; padding-top: 6px; } .details dt { width:120px; float:left; padding-left: 10px; padding-top: 6px; }
.details dd { margin-left: 50px; } .details dd { margin-left: 70px; }
.details ul { margin: 0; } .details ul { margin: 0; }
.details ul { list-style-type: none; } .details ul { list-style-type: none; }
.details li { margin-left: 30px; padding-top: 6px; } .details li { margin-left: 30px; padding-top: 6px; }

View File

@ -80,48 +80,6 @@
<?js }); ?></dl> <?js }); ?></dl>
<?js } ?> <?js } ?>
<?js
/* listing interface list at implemented class documents. */
var implements = doc.implements;
if (doc.kind === 'class' && implements && implements.length) {
?>
<h3 class="subsection-title">Implements</h3>
<ul>
<?js
implements.forEach(function(imp) {
?>
<li> <?js= self.linkto(imp) ?> </li>
<?js
});
?>
</ul>
<?js
}
?>
<?js
/* listing implemented class with this interface. */
var implemented = self.find({ 'implements': { 'isArray': true } });
if (doc.kind === 'interface' && implemented && implemented.length) {
?>
<h3 class="subsection-title">Implementations</h3>
<ul>
<?js
implemented.forEach(function(imp) {
if (imp.implements.indexOf(doc.name) > -1) {
?>
<li> <?js= self.linkto(imp.longname, self.htmlsafe(imp.longname)) ?> </li>
<?js
}
});
?>
</ul>
<?js
}
?>
<?js <?js
var mixins = self.find({kind: 'mixin', memberof: doc.longname}); var mixins = self.find({kind: 'mixin', memberof: doc.longname});
if (doc.kind !== 'globalobj' && mixins && mixins.length) { if (doc.kind !== 'globalobj' && mixins && mixins.length) {

View File

@ -39,11 +39,22 @@ if (data.defaultvalue && (data.defaultvaluetype === 'object' || data.defaultvalu
</li></dd> </li></dd>
<?js } ?> <?js } ?>
<?js if (data.implemented && data.implementProp) { ?> <?js if (data.implementations && data.implementations.length) { ?>
<dt class="implementes">Implementes:</dt> <dt class="implementations">Implementations:</dt>
<dd class="implementes"><ul class="dummy"><li> <dd class="implementations"><ul>
<?js= this.linkto(data.implementProp, this.htmlsafe(data.implementProp)) ?> <?js data.implementations.forEach(function(impl) { ?>
</li></dd> <li><?js= self.linkto(impl, self.htmlsafe(impl)) ?></li>
<?js }); ?>
</ul></dd>
<?js } ?>
<?js if (data.implements && data.implements.length) { ?>
<dt class="implements">Implements:</dt>
<dd class="implements"><ul>
<?js data.implements.forEach(function(impl) { ?>
<li><?js= self.linkto(impl, self.htmlsafe(impl)) ?></li>
<?js }); ?>
</ul></dd>
<?js } ?> <?js } ?>
<?js if (data.mixes && data.mixes.length) { ?> <?js if (data.mixes && data.mixes.length) { ?>

View File

@ -12,12 +12,13 @@ describe('@implements tag', function() {
it('MyTester has an "implements" array', function() { it('MyTester has an "implements" array', function() {
expect(Array.isArray(myTester.implements)).toBe(true); expect(Array.isArray(myTester.implements)).toBe(true);
expect(myTester.implements.length).toBe(1); expect(myTester.implements.length).toBe(1);
expect(myTester.implements[0]).toEqual('ITester'); expect(myTester.implements[0]).toBe('ITester');
}); });
it('beforeEach has "implemented" and "implementProp" property', function() { it('beforeEach has an "implements" array', function() {
expect(beforeEachMethod.implemented).toBeDefined(); expect(Array.isArray(beforeEachMethod.implements)).toBe(true);
expect(beforeEachMethod.implementProp).toBeDefined(); expect(beforeEachMethod.implements.length).toBe(1);
expect(beforeEachMethod.implements[0]).toBe('ITester#beforeEach');
}); });
it('MyWorker\'s process() method does not implement an interface', function() { it('MyWorker\'s process() method does not implement an interface', function() {