"),b.each(this.datasets,c)}}),c}(),j=function(){"use strict";function a(){i.apply(this,[].slice.call(arguments,0))}var c=i.prototype;return b.mixin(a.prototype,i.prototype,{open:function(){return!this._allDatasetsEmpty()&&this._show(),c.open.apply(this,[].slice.call(arguments,0))},close:function(){return this._hide(),c.close.apply(this,[].slice.call(arguments,0))},_onRendered:function(){return this._allDatasetsEmpty()?this._hide():this.isOpen()&&this._show(),c._onRendered.apply(this,[].slice.call(arguments,0))},_onCleared:function(){return this._allDatasetsEmpty()?this._hide():this.isOpen()&&this._show(),c._onCleared.apply(this,[].slice.call(arguments,0))},setLanguageDirection:function(a){return this.$node.css("ltr"===a?this.css.ltr:this.css.rtl),c.setLanguageDirection.apply(this,[].slice.call(arguments,0))},_hide:function(){this.$node.hide()},_show:function(){this.$node.css("display","block")}}),a}(),k=function(){"use strict";function c(c,e){var f,g,h,i,j,k,l,m,n,o,p;c=c||{},c.input||a.error("missing input"),c.menu||a.error("missing menu"),c.eventBus||a.error("missing event bus"),e.mixin(this),this.eventBus=c.eventBus,this.minLength=b.isNumber(c.minLength)?c.minLength:1,this.input=c.input,this.menu=c.menu,this.enabled=!0,this.active=!1,this.input.hasFocus()&&this.activate(),this.dir=this.input.getLangDir(),this._hacks(),this.menu.bind().onSync("selectableClicked",this._onSelectableClicked,this).onSync("asyncRequested",this._onAsyncRequested,this).onSync("asyncCanceled",this._onAsyncCanceled,this).onSync("asyncReceived",this._onAsyncReceived,this).onSync("datasetRendered",this._onDatasetRendered,this).onSync("datasetCleared",this._onDatasetCleared,this),f=d(this,"activate","open","_onFocused"),g=d(this,"deactivate","_onBlurred"),h=d(this,"isActive","isOpen","_onEnterKeyed"),i=d(this,"isActive","isOpen","_onTabKeyed"),j=d(this,"isActive","_onEscKeyed"),k=d(this,"isActive","open","_onUpKeyed"),l=d(this,"isActive","open","_onDownKeyed"),m=d(this,"isActive","isOpen","_onLeftKeyed"),n=d(this,"isActive","isOpen","_onRightKeyed"),o=d(this,"_openIfActive","_onQueryChanged"),p=d(this,"_openIfActive","_onWhitespaceChanged"),this.input.bind().onSync("focused",f,this).onSync("blurred",g,this).onSync("enterKeyed",h,this).onSync("tabKeyed",i,this).onSync("escKeyed",j,this).onSync("upKeyed",k,this).onSync("downKeyed",l,this).onSync("leftKeyed",m,this).onSync("rightKeyed",n,this).onSync("queryChanged",o,this).onSync("whitespaceChanged",p,this).onSync("langDirChanged",this._onLangDirChanged,this)}function d(a){var c=[].slice.call(arguments,1);return function(){var d=[].slice.call(arguments);b.each(c,function(b){return a[b].apply(a,d)})}}return b.mixin(c.prototype,{_hacks:function(){var c,d;c=this.input.$input||a("
"),d=this.menu.$node||a("
"),c.on("blur.tt",function(a){var e,f,g;
+e=document.activeElement,f=d.is(e),g=d.has(e).length>0,b.isMsie()&&(f||g)&&(a.preventDefault(),a.stopImmediatePropagation(),b.defer(function(){c.focus()}))}),d.on("mousedown.tt",function(a){a.preventDefault()})},_onSelectableClicked:function(a,b){this.select(b)},_onDatasetCleared:function(){this._updateHint()},_onDatasetRendered:function(a,b,c,d){this._updateHint(),this.eventBus.trigger("render",c,d,b)},_onAsyncRequested:function(a,b,c){this.eventBus.trigger("asyncrequest",c,b)},_onAsyncCanceled:function(a,b,c){this.eventBus.trigger("asynccancel",c,b)},_onAsyncReceived:function(a,b,c){this.eventBus.trigger("asyncreceive",c,b)},_onFocused:function(){this._minLengthMet()&&this.menu.update(this.input.getQuery())},_onBlurred:function(){this.input.hasQueryChangedSinceLastFocus()&&this.eventBus.trigger("change",this.input.getQuery())},_onEnterKeyed:function(a,b){var c;(c=this.menu.getActiveSelectable())&&this.select(c)&&b.preventDefault()},_onTabKeyed:function(a,b){var c;(c=this.menu.getActiveSelectable())?this.select(c)&&b.preventDefault():(c=this.menu.getTopSelectable())&&this.autocomplete(c)&&b.preventDefault()},_onEscKeyed:function(){this.close()},_onUpKeyed:function(){this.moveCursor(-1)},_onDownKeyed:function(){this.moveCursor(1)},_onLeftKeyed:function(){"rtl"===this.dir&&this.input.isCursorAtEnd()&&this.autocomplete(this.menu.getTopSelectable())},_onRightKeyed:function(){"ltr"===this.dir&&this.input.isCursorAtEnd()&&this.autocomplete(this.menu.getTopSelectable())},_onQueryChanged:function(a,b){this._minLengthMet(b)?this.menu.update(b):this.menu.empty()},_onWhitespaceChanged:function(){this._updateHint()},_onLangDirChanged:function(a,b){this.dir!==b&&(this.dir=b,this.menu.setLanguageDirection(b))},_openIfActive:function(){this.isActive()&&this.open()},_minLengthMet:function(a){return a=b.isString(a)?a:this.input.getQuery()||"",a.length>=this.minLength},_updateHint:function(){var a,c,d,e,f,h,i;a=this.menu.getTopSelectable(),c=this.menu.getSelectableData(a),d=this.input.getInputValue(),!c||b.isBlankString(d)||this.input.hasOverflow()?this.input.clearHint():(e=g.normalizeQuery(d),f=b.escapeRegExChars(e),h=new RegExp("^(?:"+f+")(.+$)","i"),i=h.exec(c.val),i&&this.input.setHint(d+i[1]))},isEnabled:function(){return this.enabled},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},isActive:function(){return this.active},activate:function(){return this.isActive()?!0:!this.isEnabled()||this.eventBus.before("active")?!1:(this.active=!0,this.eventBus.trigger("active"),!0)},deactivate:function(){return this.isActive()?this.eventBus.before("idle")?!1:(this.active=!1,this.close(),this.eventBus.trigger("idle"),!0):!0},isOpen:function(){return this.menu.isOpen()},open:function(){return this.isOpen()||this.eventBus.before("open")||(this.menu.open(),this._updateHint(),this.eventBus.trigger("open")),this.isOpen()},close:function(){return this.isOpen()&&!this.eventBus.before("close")&&(this.menu.close(),this.input.clearHint(),this.input.resetInputValue(),this.eventBus.trigger("close")),!this.isOpen()},setVal:function(a){this.input.setQuery(b.toStr(a))},getVal:function(){return this.input.getQuery()},select:function(a){var b=this.menu.getSelectableData(a);return b&&!this.eventBus.before("select",b.obj)?(this.input.setQuery(b.val,!0),this.eventBus.trigger("select",b.obj),this.close(),!0):!1},autocomplete:function(a){var b,c,d;return b=this.input.getQuery(),c=this.menu.getSelectableData(a),d=c&&b!==c.val,d&&!this.eventBus.before("autocomplete",c.obj)?(this.input.setQuery(c.val),this.eventBus.trigger("autocomplete",c.obj),!0):!1},moveCursor:function(a){var b,c,d,e,f;return b=this.input.getQuery(),c=this.menu.selectableRelativeToCursor(a),d=this.menu.getSelectableData(c),e=d?d.obj:null,f=this._minLengthMet()&&this.menu.update(b),f||this.eventBus.before("cursorchange",e)?!1:(this.menu.setCursor(c),d?this.input.setInputValue(d.val):(this.input.resetInputValue(),this._updateHint()),this.eventBus.trigger("cursorchange",e),!0)},destroy:function(){this.input.destroy(),this.menu.destroy()}}),c}();!function(){"use strict";function e(b,c){b.each(function(){var b,d=a(this);(b=d.data(p.typeahead))&&c(b,d)})}function f(a,b){return a.clone().addClass(b.classes.hint).removeData().css(b.css.hint).css(l(a)).prop("readonly",!0).removeAttr("id name placeholder required").attr({autocomplete:"off",spellcheck:"false",tabindex:-1})}function h(a,b){a.data(p.attrs,{dir:a.attr("dir"),autocomplete:a.attr("autocomplete"),spellcheck:a.attr("spellcheck"),style:a.attr("style")}),a.addClass(b.classes.input).attr({autocomplete:"off",spellcheck:!1});try{!a.attr("dir")&&a.attr("dir","auto")}catch(c){}return a}function l(a){return{backgroundAttachment:a.css("background-attachment"),backgroundClip:a.css("background-clip"),backgroundColor:a.css("background-color"),backgroundImage:a.css("background-image"),backgroundOrigin:a.css("background-origin"),backgroundPosition:a.css("background-position"),backgroundRepeat:a.css("background-repeat"),backgroundSize:a.css("background-size")}}function m(a){var c,d;c=a.data(p.www),d=a.parent().filter(c.selectors.wrapper),b.each(a.data(p.attrs),function(c,d){b.isUndefined(c)?a.removeAttr(d):a.attr(d,c)}),a.removeData(p.typeahead).removeData(p.www).removeData(p.attr).removeClass(c.classes.input),d.length&&(a.detach().insertAfter(d),d.remove())}function n(c){var d,e;return d=b.isJQuery(c)||b.isElement(c),e=d?a(c).first():[],e.length?e:null}var o,p,q;o=a.fn.typeahead,p={www:"tt-www",attrs:"tt-attrs",typeahead:"tt-typeahead"},q={initialize:function(e,l){function m(){var c,m,q,r,s,t,u,v,w,x,y;b.each(l,function(a){a.highlight=!!e.highlight}),c=a(this),m=a(o.html.wrapper),q=n(e.hint),r=n(e.menu),s=e.hint!==!1&&!q,t=e.menu!==!1&&!r,s&&(q=f(c,o)),t&&(r=a(o.html.menu).css(o.css.menu)),q&&q.val(""),c=h(c,o),(s||t)&&(m.css(o.css.wrapper),c.css(s?o.css.input:o.css.inputWithNoHint),c.wrap(m).parent().prepend(s?q:null).append(t?r:null)),y=t?j:i,u=new d({el:c}),v=new g({hint:q,input:c},o),w=new y({node:r,datasets:l},o),x=new k({input:v,menu:w,eventBus:u,minLength:e.minLength},o),c.data(p.www,o),c.data(p.typeahead,x)}var o;return l=b.isArray(l)?l:[].slice.call(arguments,1),e=e||{},o=c(e.classNames),this.each(m)},isEnabled:function(){var a;return e(this.first(),function(b){a=b.isEnabled()}),a},enable:function(){return e(this,function(a){a.enable()}),this},disable:function(){return e(this,function(a){a.disable()}),this},isActive:function(){var a;return e(this.first(),function(b){a=b.isActive()}),a},activate:function(){return e(this,function(a){a.activate()}),this},deactivate:function(){return e(this,function(a){a.deactivate()}),this},isOpen:function(){var a;return e(this.first(),function(b){a=b.isOpen()}),a},open:function(){return e(this,function(a){a.open()}),this},close:function(){return e(this,function(a){a.close()}),this},select:function(b){var c=!1,d=a(b);return e(this.first(),function(a){c=a.select(d)}),c},autocomplete:function(b){var c=!1,d=a(b);return e(this.first(),function(a){c=a.autocomplete(d)}),c},moveCursor:function(a){var b=!1;return e(this.first(),function(c){b=c.moveCursor(a)}),b},val:function(a){var b;return arguments.length?(e(this,function(b){b.setVal(a)}),this):(e(this.first(),function(a){b=a.getVal()}),b)},destroy:function(){return e(this,function(a,b){m(b),a.destroy()}),this}},a.fn.typeahead=function(a){return q[a]?q[a].apply(this,[].slice.call(arguments,1)):q.initialize.apply(this,arguments)},a.fn.typeahead.noConflict=function(){return a.fn.typeahead=o,this}}()});
diff --git a/lib/src/html_generator.dart b/lib/src/html_generator.dart
index 8b37412b7e..f41416ddf1 100644
--- a/lib/src/html_generator.dart
+++ b/lib/src/html_generator.dart
@@ -5,7 +5,8 @@
library dartdoc.html_generator;
import 'dart:async' show Future;
-import 'dart:io';
+import 'dart:io' show Directory, File;
+import 'dart:convert' show JSON;
import 'dart:typed_data' show Uint8List;
import 'package:mustache4dart/mustache4dart.dart';
@@ -17,6 +18,7 @@ import 'resources.g.dart' as resources;
import '../generator.dart';
import '../markdown_processor.dart';
import '../resource_loader.dart' as loader;
+import 'io_utils.dart' show createOutputFile;
String dartdocVersion = 'unknown';
@@ -156,7 +158,7 @@ class HtmlGeneratorInstance {
final Package package;
final Directory out;
- final List _htmlFiles = [];
+ final List documentedElements = [];
HtmlGeneratorInstance(this.url, this._templates, this.package, this.out);
@@ -166,13 +168,30 @@ class HtmlGeneratorInstance {
if (package != null) {
_generateDocs();
+ _generateSearchIndex();
+ // TODO: generate sitemap
}
- //if (url != null) generateSiteMap();
-
await _copyResources();
}
+ void _generateSearchIndex() {
+ File jsonFile = createOutputFile(out, 'index.json');
+ String json = JSON.encode(documentedElements.map((ModelElement e) {
+ // TODO: find a better string for type
+ Map data = {'name': e.name, 'href': e.href, 'type': e.kind};
+ if (e is EnclosedElement) {
+ EnclosedElement ee = e as EnclosedElement;
+ data['enclosedBy'] = {
+ 'name': ee.enclosingElement.name,
+ 'type': ee.enclosingElement.kind
+ };
+ }
+ return data;
+ }).toList());
+ jsonFile.writeAsStringSync(json);
+ }
+
void _generateDocs() {
if (package == null) return;
@@ -354,22 +373,16 @@ class HtmlGeneratorInstance {
}
}
- File _createOutputFile(String filename) {
- File f = new File(path.join(out.path, filename));
- if (!f.existsSync()) f.createSync(recursive: true);
- _htmlFiles.add(filename);
- return f;
- }
-
void _build(String filename, TemplateRenderer template, TemplateData data) {
String content = template(data,
assumeNullNonExistingProperty: false, errorOnMissingProperty: true);
_writeFile(filename, content);
+ if (data.self is ModelElement) documentedElements.add(data.self);
}
void _writeFile(String filename, String content) {
- File f = _createOutputFile(filename);
+ File f = createOutputFile(out, filename);
f.writeAsStringSync(content);
}
}
diff --git a/lib/src/io_utils.dart b/lib/src/io_utils.dart
index 3661890293..26d7cd9b11 100644
--- a/lib/src/io_utils.dart
+++ b/lib/src/io_utils.dart
@@ -9,6 +9,12 @@ import 'dart:io';
import 'package:path/path.dart' as path;
+File createOutputFile(Directory destination, String filename) {
+ File f = new File(path.join(destination.path, filename));
+ if (!f.existsSync()) f.createSync(recursive: true);
+ return f;
+}
+
/// Lists the contents of [dir].
///
/// If [recursive] is `true`, lists subdirectory contents (defaults to `false`).
diff --git a/lib/src/model.dart b/lib/src/model.dart
index 3078496492..f714d07951 100644
--- a/lib/src/model.dart
+++ b/lib/src/model.dart
@@ -5,19 +5,21 @@
/// The models used to represent Dart code
library dartdoc.models;
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/ast.dart' show AnnotatedNode, Annotation;
import 'package:analyzer/src/generated/element.dart';
-import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/resolver.dart'
+ show Namespace, NamespaceBuilder, InheritanceManager, MemberMap;
import 'package:analyzer/src/generated/utilities_dart.dart' show ParameterKind;
-import 'package:quiver/core.dart';
+import 'package:quiver/core.dart' show hash3;
-import 'html_utils.dart';
-import 'model_utils.dart';
-import 'package_meta.dart';
+import 'html_utils.dart' show stripComments, htmlEscape;
+import 'model_utils.dart' show isPrivate, isPublic, getAllSupertypes;
+import 'package_meta.dart' show PackageMeta, FileContents;
-import '../markdown_processor.dart';
+import '../markdown_processor.dart' show Documentation, renderMarkdownToHtml;
-int byName(a, b) => a.name.toUpperCase().compareTo(b.name.toUpperCase());
+int byName(Nameable a, Nameable b) =>
+ a.name.toUpperCase().compareTo(b.name.toUpperCase());
final Map> _implementors = new Map();
@@ -48,7 +50,19 @@ void _addToImplementors(Class c) {
}
}
-abstract class ModelElement implements Comparable {
+/// An element that is enclosed by some other element.
+///
+/// Libraries are not enclosed.
+abstract class EnclosedElement {
+ ModelElement get enclosingElement;
+}
+
+/// Something that has a name.
+abstract class Nameable {
+ String get name;
+}
+
+abstract class ModelElement implements Comparable, Nameable {
final Element element;
final Library library;
@@ -111,6 +125,9 @@ abstract class ModelElement implements Comparable {
}
}
+ /// A human-friendly name for the kind of element this is.
+ String get kind;
+
String get _computeDocumentationComment =>
element.computeDocumentationComment();
@@ -362,14 +379,20 @@ abstract class ModelElement implements Comparable {
}
}
+// TODO: how do we get rid of this class?
class Dynamic extends ModelElement {
Dynamic(DynamicElementImpl element, Library library)
: super(element, library);
+ ModelElement get enclosingElement => throw new UnsupportedError('');
+
String get _href => throw new StateError('dynamic should not have an href');
+
+ @override
+ String get kind => 'dynamic';
}
-class Package {
+class Package implements Nameable {
final List _libraries = [];
final PackageMeta packageMeta;
String _docsAsHtml;
@@ -506,6 +529,12 @@ class Library extends ModelElement {
return library;
}
+ @override
+ String get kind => 'library';
+
+ /// Libraries are not enclosed by anything.
+ ModelElement get enclosingElement => null;
+
Library get library => this;
Iterable get _exportedNamespace {
@@ -732,7 +761,7 @@ class Library extends ModelElement {
String get _href => '$dirName/$fileName';
}
-class Class extends ModelElement {
+class Class extends ModelElement implements EnclosedElement {
List _mixins;
ElementType _supertype;
List _interfaces;
@@ -800,6 +829,9 @@ class Class extends ModelElement {
}).where((it) => it != null).toList(growable: false);
}
+ /// Returns the library that encloses this element.
+ ModelElement get enclosingElement => library;
+
String get nameWithGenerics {
if (!modelType.isParameterizedType) return name;
return '$name<${_typeParameters.map((t) => t.name).join(', ')}>';
@@ -810,6 +842,7 @@ class Class extends ModelElement {
return new TypeParameter(f, lib);
}).toList();
+ @override
String get kind => 'class';
String get fileName => "${name}-class.html";
@@ -1274,12 +1307,16 @@ abstract class SourceCodeMixin {
Element get element;
}
-class ModelFunction extends ModelElement with SourceCodeMixin {
+class ModelFunction extends ModelElement
+ with SourceCodeMixin
+ implements EnclosedElement {
ModelFunction(FunctionElement element, Library library)
: super(element, library) {
_modelType = new ElementType(_func.type, this);
}
+ ModelElement get enclosingElement => library;
+
FunctionElement get _func => (element as FunctionElement);
bool get isStatic => _func.isStatic;
@@ -1288,11 +1325,14 @@ class ModelFunction extends ModelElement with SourceCodeMixin {
String get fileName => "$name.html";
+ @override
+ String get kind => 'function';
+
@override
String get _href => '${library.dirName}/$fileName';
}
-class Typedef extends ModelElement {
+class Typedef extends ModelElement implements EnclosedElement {
FunctionTypeAliasElement get _typedef =>
(element as FunctionTypeAliasElement);
@@ -1303,6 +1343,12 @@ class Typedef extends ModelElement {
}
}
+ @override
+ String get kind => 'typedef';
+
+ @override
+ ModelElement get enclosingElement => library;
+
String get fileName => '$name.html';
String get linkedReturnType => modelType != null
@@ -1312,7 +1358,8 @@ class Typedef extends ModelElement {
String get _href => '${library.dirName}/$fileName';
}
-class Field extends ModelElement {
+// TODO: rename this to property
+class Field extends ModelElement implements EnclosedElement {
String _constantValue;
bool _isInherited = false;
@@ -1328,6 +1375,13 @@ class Field extends ModelElement {
_setModelType();
}
+ @override
+ String get kind => 'property';
+
+ @override
+ ModelElement get enclosingElement =>
+ new ModelElement.from(_field.enclosingElement, library);
+
@override
String get _computeDocumentationComment {
var buffer = new StringBuffer();
@@ -1439,12 +1493,19 @@ class EnumField extends Field {
String get linkedName => name;
}
-class Constructor extends ModelElement {
+class Constructor extends ModelElement implements EnclosedElement {
ConstructorElement get _constructor => (element as ConstructorElement);
Constructor(ConstructorElement element, Library library)
: super(element, library);
+ @override
+ String get kind => 'constructor';
+
+ @override
+ ModelElement get enclosingElement =>
+ new ModelElement.from(_constructor.enclosingElement, library);
+
@override
String get _href =>
'${library.dirName}/${_constructor.enclosingElement.name}/$name.html';
@@ -1471,7 +1532,9 @@ class Constructor extends ModelElement {
}
}
-class Method extends ModelElement with SourceCodeMixin {
+class Method extends ModelElement
+ with SourceCodeMixin
+ implements EnclosedElement {
bool _isInherited = false;
MethodElement get _method => (element as MethodElement);
@@ -1486,6 +1549,13 @@ class Method extends ModelElement with SourceCodeMixin {
_isInherited = true;
}
+ @override
+ String get kind => 'method';
+
+ @override
+ ModelElement get enclosingElement =>
+ new ModelElement.from(_method.enclosingElement, library);
+
Method get overriddenElement {
ClassElement parent = element.enclosingElement;
for (InterfaceType t in getAllSupertypes(parent)) {
@@ -1566,12 +1636,19 @@ class Operator extends Method {
}
/// Getters and setters.
-class Accessor extends ModelElement {
+class Accessor extends ModelElement implements EnclosedElement {
PropertyAccessorElement get _accessor => (element as PropertyAccessorElement);
Accessor(PropertyAccessorElement element, Library library)
: super(element, library);
+ @override
+ String get kind => 'accessor';
+
+ @override
+ ModelElement get enclosingElement =>
+ new ModelElement.from(_accessor.enclosingElement, library);
+
bool get isGetter => _accessor.isGetter;
@override
@@ -1580,7 +1657,7 @@ class Accessor extends ModelElement {
}
/// Top-level variables. But also picks up getters and setters?
-class TopLevelVariable extends ModelElement {
+class TopLevelVariable extends ModelElement implements EnclosedElement {
TopLevelVariableElement get _variable => (element as TopLevelVariableElement);
TopLevelVariable(TopLevelVariableElement element, Library library)
@@ -1597,6 +1674,12 @@ class TopLevelVariable extends ModelElement {
}
}
+ @override
+ String get kind => 'top-level property';
+
+ @override
+ ModelElement get enclosingElement => library;
+
bool get isFinal => _variable.isFinal;
bool get isConst => _variable.isConst;
@@ -1636,7 +1719,7 @@ class TopLevelVariable extends ModelElement {
String get _href => '${library.dirName}/${name}.html';
}
-class Parameter extends ModelElement {
+class Parameter extends ModelElement implements EnclosedElement {
Parameter(ParameterElement element, Library library)
: super(element, library) {
var t = _parameter.type;
@@ -1644,6 +1727,13 @@ class Parameter extends ModelElement {
t, new ModelElement.from(t.element, package._getLibraryFor(t.element)));
}
+ @override
+ String get kind => 'parameter';
+
+ @override
+ ModelElement get enclosingElement =>
+ new ModelElement.from(_parameter.enclosingElement, library);
+
ParameterElement get _parameter => element as ParameterElement;
bool get isOptional => _parameter.parameterKind.isOptional;
@@ -1690,6 +1780,9 @@ class TypeParameter extends ModelElement {
_modelType = new ElementType(_typeParameter.type, this);
}
+ @override
+ String get kind => 'type parameter';
+
TypeParameterElement get _typeParameter => element as TypeParameterElement;
String toString() => element.name;
diff --git a/lib/src/resources.g.dart b/lib/src/resources.g.dart
index 59134e9621..cc4b41cd16 100644
--- a/lib/src/resources.g.dart
+++ b/lib/src/resources.g.dart
@@ -8,6 +8,7 @@ const List resource_names = const [
'package:dartdoc/resources/prettify.js',
'package:dartdoc/resources/script.js',
'package:dartdoc/resources/styles.css',
+ 'package:dartdoc/resources/typeahead.bundle.min.js',
'package:dartdoc/resources/css/bootstrap.css',
'package:dartdoc/resources/css/bootstrap.css.map',
'package:dartdoc/resources/css/bootstrap.min.css'
diff --git a/lib/templates/_footer.html b/lib/templates/_footer.html
index 563cfbc879..32ecc7903e 100644
--- a/lib/templates/_footer.html
+++ b/lib/templates/_footer.html
@@ -1,3 +1,4 @@
+