diff --git a/lib/dartdoc.dart b/lib/dartdoc.dart index 10cd8ea8a1..1b684d7fe1 100644 --- a/lib/dartdoc.dart +++ b/lib/dartdoc.dart @@ -14,14 +14,10 @@ import 'package:analyzer/src/generated/sdk.dart'; import 'package:analyzer/src/generated/sdk_io.dart'; import 'package:analyzer/src/generated/source_io.dart'; - -import 'src/css.dart'; -import 'src/helpers.dart'; -import 'src/html_gen.dart'; +import 'src/generator.dart'; import 'src/io_utils.dart'; +import 'src/model.dart'; import 'src/model_utils.dart'; -import 'src/package_utils.dart'; -import 'src/utils.dart'; const String DEFAULT_OUTPUT_DIRECTORY = 'docs'; @@ -31,11 +27,9 @@ class DartDoc { List _excludes; Directory _rootDir; - final CSS css = new CSS(); - HtmlGenerator html; Directory out; Set libraries = new Set(); - Generator generator; + HtmlGenerator generator; DartDoc(this._rootDir, this._excludes); @@ -54,19 +48,16 @@ class DartDoc { libs.sort(elementCompare); libraries.addAll(libs); - generator = new GeneratorHelper(libraries); + // create the out directory out = new Directory(DEFAULT_OUTPUT_DIRECTORY); if (!out.existsSync()) { out.createSync(recursive: true); } + + generator = new HtmlGenerator(new Package(libraries, _rootDir.path), out); // generate the docs - html = new HtmlGenerator(); - generatePackage(); - libraries.forEach((lib) => generateLibrary(lib)); - // copy the css resource into 'out' - File f = joinFile(new Directory(out.path), [css.getCssName()]); - f.writeAsStringSync(css.getCssContent()); + generator.generate(); double seconds = stopwatch.elapsedMilliseconds / 1000.0; print(''); @@ -114,489 +105,6 @@ class DartDoc { return new File(Platform.executable).parent.parent; } - void generatePackage() { - var packageName = getPackageName(_rootDir.path); - var packageDesc = getPackageDescription(_rootDir.path); - var packageVersion = getPackageVersion(_rootDir.path); - if (packageName.isNotEmpty) { - File f = joinFile(new Directory(out.path), ['${packageName}_package.html']); - print('generating ${f.path}'); - html = new HtmlGenerator(); - html.start(title: 'Package ${packageName}', cssRef: css.getCssName()); - generateHeader(); - - html.startTag('div', attributes: "class='container'", newLine: false); - html.writeln(); - html.startTag('div', attributes: "class='row'", newLine: false); - html.writeln(); - html.startTag('div', attributes: "class='span3'"); - html.startTag('ul', attributes: 'class="nav nav-tabs nav-stacked left-nav"'); - html.startTag('li', attributes: 'class="active"', newLine: false); - html.write('' - ' ' - '${packageName}-${packageVersion}'); - html.endTag(); //li - html.endTag(); //ul - html.endTag(); - html.startTag('div', attributes: "class='span9'"); - html.tag('h1', contents: packageName); - html.writeln('
'); - html.write(packageDesc); - html.startTag('dl'); - html.startTag('h4'); - html.tag('dt', contents: 'Libraries'); - html.endTag(); - html.startTag('dd'); - for (LibraryElement lib in libraries) { - html.writeln(' ${lib.name}
'); - } - html.endTag(); - html.endTag(); // div.container - generateFooter(); - html.end(); - f.writeAsStringSync(html.toString()); - } - - } - - void generateLibrary(LibraryElement library) { - File f = joinFile(new Directory(out.path), [getFileNameFor(library)]); - print('generating ${f.path}'); - html = new HtmlGenerator(); - html.start(title: 'Library ${library.name}', cssRef: css.getCssName()); - - generateHeader(); - - html.startTag('div', attributes: "class='container'", newLine: false); - html.writeln(); - html.startTag('div', attributes: "class='row'", newLine: false); - html.writeln(); - - // left nav - html.startTag('div', attributes: "class='span3'"); - html.startTag('ul', attributes: 'class="nav nav-tabs nav-stacked left-nav"'); - html.startTag('li', attributes: 'class="active"', newLine: false); - html.write('' - ' ' - '${library.name}'); - html.endTag(); // li - html.endTag(); // ul.nav - html.endTag(); // div.span3 - - // main content - html.startTag('div', attributes: "class='span9'"); - - html.tag('h1', contents: library.name); - - if (!library.exportedLibraries.isEmpty) { - html.startTag('p'); - html.write('exports '); - for (int i = 0; i < library.exportedLibraries.length; i++) { - if (i > 0) { - html.write(', '); - } - - LibraryElement lib = library.exportedLibraries[i]; - if (libraries.contains(lib)) { - html.write('${lib.name}'); - } else { - html.write(lib.name); - } - } - html.endTag(); - } - - html.writeln('
'); - - LibraryHelper lib = new LibraryHelper(library); - - html.startTag('dl', attributes: "class=dl-horizontal"); - - List variables = lib.getVariables(); - List accessors = lib.getAccessors(); - List functions = lib.getFunctions(); - List typedefs = lib.getTypedefs(); - List types = lib.getTypes(); - - createToc(variables); - createToc(accessors); - createToc(functions); - createToc(typedefs); - createToc(types); - - html.endTag(); // dl - - printComments(library); - - generateElements(variables); - generateElements(accessors); - generateElements(functions); - generateElements(typedefs); - - types.forEach(generateClass); - - html.writeln('
'); - - html.endTag(); // div.span9 - - html.endTag(); // div.row - - html.endTag(); // div.container - - generateFooter(); - - html.end(); - - // write the file contents - f.writeAsStringSync(html.toString()); - } - - void generateHeader() { - // header - html.startTag('header'); - html.endTag(); - } - - void generateFooter() { - // footer - html.startTag('footer'); -// html.startTag('div', 'class="navbar navbar-fixed-bottom"'); -// html.startTag('div', 'class="navbar-inner"'); -// html.startTag('div', 'class="container" style="width: auto; padding: 0 20px;"'); -// html.tag('a', 'Title'); //Title -// html.startTag('ul', 'class="nav"'); -// html.tag('li', 'Link'); -// html.endTag(); -// html.endTag(); -// html.endTag(); -// html.endTag(); - html.endTag(); - } - - void createToc(List elements) { - if (!elements.isEmpty) { - html.tag('dt', contents: elements[0].typeName); - html.startTag('dd'); - for (ElementHelper e in elements) { - html.writeln('${createIconFor(e.element)}${e.createLinkedSummary(generator)}
'); - } - html.endTag(); - } - } - - String getFileNameFor(LibraryElement library) { - return '${library.name}.html'; - } - - void generateElements(List elements, [bool header = true]) { - if (!elements.isEmpty) { - html.tag('h4', contents: elements[0].typeName); - if (header) { - html.startTag('div', attributes: "class=indent"); - } - elements.forEach(generateElement); - if (header) { - html.endTag(); - } - } - } - - void generateAnnotations(List annotations) { - if (!annotations.isEmpty) { - html.write(' '); - for (ElementAnnotation a in annotations) { - Element e = a.element; - // TODO: I don't believe we get back the right elements for const - // ctor annotations - html.writeln('@${e.name} '); - } - html.writeln('
'); - } - } - - void generateElement(ElementHelper f) { - html.startTag('b', newLine: false); - html.write('${createAnchor(f.element)}'); - generateAnnotations(f.element.metadata); - html.write(createIconFor(f.element)); - if (f.element is MethodElement) { - html.write(generateOverrideIcon(f.element as MethodElement)); - } - html.write(f.createLinkedDescription(generator)); - html.endTag(); - printComments(f.element); - } - - String createIconFor(Element e) { - if (e is PropertyAccessorElement) { - PropertyAccessorElement a = e; - - if (a.isGetter) { - return ' '; - } else { - return ' '; - } - } else if (e is ClassElement) { - return ' '; - } else if (e is FunctionTypeAliasElement) { - return ' '; - } else if (e is PropertyInducingElement) { - return ' '; - } else if (e is ConstructorElement) { - return ' '; - } else if (e is ExecutableElement) { - return ' '; - } else { - return ''; - } - } - - String generateOverrideIcon(MethodElement element) { - Element o = getOverriddenElement(element); - - if (o == null) { - return ''; - } else if (!generator.isDocumented(o)) { - return " "; - } else { - return "" " "; - } - } - - String getNameFor(Element e) { - ClassElement c = getEnclosingElement(e); - // TODO: upscale this! handle ctors - String ext = (e is ExecutableElement) ? '()' : ''; - return '${c.name}.${htmlEscape(e.name)}${ext}'; - } - - void generateClass(ClassHelper helper) { - ClassElement c = helper.element; - html.write(createAnchor(c)); - html.writeln('
'); - html.startTag('h4'); - generateAnnotations(c.metadata); - html.write(createIconFor(c)); - if (c.isAbstract) { - html.write('Abstract class ${c.name}'); - } else { - html.write('Class ${c.name}'); - } - if (c.supertype != null && c.supertype.element.supertype != null) { - html.write(' extends ${generator.createLinkedTypeName(c.supertype)}'); - } - if (!c.mixins.isEmpty) { - html.write(' with'); - for (int i = 0; i < c.mixins.length; i++) { - if (i == 0) { - html.write(' '); - } else { - html.write(', '); - } - html.write(generator.createLinkedTypeName(c.mixins[i])); - } - } - - if (!c.interfaces.isEmpty) { - html.write(' implements'); - for (int i = 0; i < c.interfaces.length; i++) { - if (i == 0) { - html.write(' '); - } else { - html.write(', '); - } - html.write(generator.createLinkedTypeName(c.interfaces[i])); - } - } - - html.endTag(); - - html.startTag('dl', attributes: 'class=dl-horizontal'); - createToc(helper.getStaticFields()); - createToc(helper.getInstanceFields()); - createToc(helper.getAccessors()); - createToc(helper.getCtors()); - createToc(helper.getMethods()); - html.endTag(); - - printComments(c); - - generateElements(helper.getStaticFields(), false); - generateElements(helper.getInstanceFields(), false); - generateElements(helper.getAccessors(), false); - generateElements(helper.getCtors(), false); - generateElements(helper.getMethods(), false); - } - - void printComments(Element e, [bool indent = true]) { - String comments = getDocumentationFor(e); - if (comments != null) { - if (indent) { - html.startTag('div', attributes: "class=indent"); - } - html.tag('p', contents: prettifyDocs(new Resolver(generator, e), comments)); - if (indent) { - html.endTag(); - } - } else { - if (indent) { - html.tag('div', attributes: "class=indent"); - } - } - } -} - -class Resolver extends CodeResolver { - Generator generator; - Element element; - - Resolver(this.generator, this.element); - - String resolveCodeReference(String reference) { - Element e = (element as ElementImpl).getChild(reference); - - if (e is LocalElement /*|| e is TypeVariableElement*/) { - e = null; - } - if (e != null) { - return generator.createLinkedName(e, true); - } else { - //return "$reference"; - return "$reference"; - } - } -} - -class GeneratorHelper implements Generator { - - Set libraries; - - GeneratorHelper(this.libraries); - - bool isDocumented(Element e) { - return libraries.contains(e.library); - } - - - String createLinkedName(Element e, [bool appendParens = false]) { - if (e == null) { - return ''; - } - if (!isDocumented(e)) { - return htmlEscape(e.name); - } - if (e.name.startsWith('_')) { - return htmlEscape(e.name); - } - ClassElement c = getEnclosingElement(e); - if (c != null && c.name.startsWith('_')) { - return '${c.name}.${htmlEscape(e.name)}'; - } - if (c != null && e is ConstructorElement) { - String name; - if (e.name.isEmpty) { - name = c.name; - } else { - name = '${c.name}.${htmlEscape(e.name)}'; - } - if (appendParens) { - return "${name}()"; - } else { - return "${name}"; - } - } else { - String append = ''; - - if (appendParens && (e is MethodElement || e is FunctionElement)) { - append = '()'; - } - return "${htmlEscape(e.name)}$append"; - } - } - - String createLinkedTypeName(DartType type) { - StringBuffer buf = new StringBuffer(); - - if (type is TypeParameterType) { - buf.write(type.element.name); - } else { - buf.write(createLinkedName(type.element)); - } - - if (type is ParameterizedType) { - ParameterizedType pType = type; - - if (!pType.typeArguments.isEmpty) { - buf.write('<'); - for (int i = 0; i < pType.typeArguments.length; i++) { - if (i > 0) { - buf.write(', '); - } - DartType t = pType.typeArguments[i]; - buf.write(createLinkedTypeName(t)); - } - buf.write('>'); - } - } - return buf.toString(); - } - - String createLinkedReturnTypeName(FunctionType type) { - if (type.returnType.element == null) { - if (type.returnType.name != null) { - return type.returnType.name; - } else { - return ''; - } - } else { - return createLinkedTypeName(type.returnType); - } - } - - String printParams(List params) { - StringBuffer buf = new StringBuffer(); - - for (ParameterElement p in params) { - if (buf.length > 0) { - buf.write(', '); - } - - if (p.type != null && p.type.name != null) { - buf.write(createLinkedTypeName(p.type)); - buf.write(' '); - } - - buf.write(p.name); - } - - return buf.toString(); - } - - String createHrefFor(Element e) { - if (!isDocumented(e)) { - return ''; - } - - ClassElement c = getEnclosingElement(e); - - if (c != null) { - return '${getFileNameFor(e.library)}#${c.name}.${escapeBrackets(e.name)}'; - } else { - return '${getFileNameFor(e.library)}#${e.name}'; - } - } - - } - -String createAnchor(Element e) { - ClassElement c = getEnclosingElement(e); - - if (c != null) { - return ''; - } else { - return ''; - } -} diff --git a/lib/src/css.dart b/lib/src/css.dart index 68053e0498..383a9d1309 100644 --- a/lib/src/css.dart +++ b/lib/src/css.dart @@ -1,3 +1,6 @@ +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. library css; diff --git a/lib/src/generator.dart b/lib/src/generator.dart new file mode 100644 index 0000000000..d02200e2af --- /dev/null +++ b/lib/src/generator.dart @@ -0,0 +1,539 @@ +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +library dartdoc.generator; + +import 'dart:io'; + +import 'css.dart'; +import 'html_gen.dart'; +import 'html_utils.dart'; +import 'io_utils.dart'; +import 'model.dart'; + +/// Generates the HTML files +class HtmlGenerator { + + Directory out; + Package package; + HtmlHelper html = new HtmlHelper(); + CSS css = new CSS(); + HtmlGeneratorHelper helper; + + HtmlGenerator(this.package, this.out) { + helper = new HtmlGeneratorHelper(package); + } + + void generate() { + generatePackage(); + package.libraries.forEach((lib) => generateLibrary(lib)); + // copy the css resource into 'out' + File f = joinFile(new Directory(out.path), [css.getCssName()]); + f.writeAsStringSync(css.getCssContent()); + } + + void generatePackage() { + var packageName = package.name; + var packageDesc = package.description; + var packageVersion = package.version; + if (packageName.isNotEmpty) { + File f = joinFile(new Directory(out.path), ['${packageName}_package.html']); + print('generating ${f.path}'); + + html.start(title: 'Package ${packageName}', cssRef: css.getCssName()); + html.generateHeader(); + html.startTag('div', attributes: "class='container'", newLine: false); + html.writeln(); + html.startTag('div', attributes: "class='row'", newLine: false); + html.writeln(); + html.startTag('div', attributes: "class='span3'"); + html.startTag('ul', attributes: 'class="nav nav-tabs nav-stacked left-nav"'); + html.startTag('li', attributes: 'class="active"', newLine: false); + html.write('' ' ' '${packageName}-${packageVersion}'); + html.endTag(); //li + html.endTag(); //ul + html.endTag(); + html.startTag('div', attributes: "class='span9'"); + html.tag('h1', contents: packageName); + html.writeln('
'); + html.write(packageDesc); + html.startTag('dl'); + html.startTag('h4'); + html.tag('dt', contents: 'Libraries'); + html.endTag(); + html.startTag('dd'); + for (Library lib in package.libraries) { + html.writeln(' ${lib.name}
'); + } + html.endTag(); + html.endTag(); // div.container + html.generateFooter(); + html.end(); + f.writeAsStringSync(html.toString()); + } + } + + void generateLibrary(Library library) { + File f = joinFile(new Directory(out.path), [_getFileNameFor(library)]); + print('generating ${f.path}'); + html = new HtmlHelper(); + html.start(title: 'Library ${library.name}', cssRef: css.getCssName()); + + html.generateHeader(); + + html.startTag('div', attributes: "class='container'", newLine: false); + html.writeln(); + html.startTag('div', attributes: "class='row'", newLine: false); + html.writeln(); + + // left nav + html.startTag('div', attributes: "class='span3'"); + html.startTag('ul', attributes: 'class="nav nav-tabs nav-stacked left-nav"'); + html.startTag('li', attributes: 'class="active"', newLine: false); + html.write('' ' ' '${library.name}'); + html.endTag(); // li + html.endTag(); // ul.nav + html.endTag(); // div.span3 + + // main content + html.startTag('div', attributes: "class='span9'"); + + html.tag('h1', contents: library.name); + + if (!library.exported.isEmpty) { + html.startTag('p'); + html.write('exports '); + for (int i = 0; i < library.exported.length; i++) { + if (i > 0) { + html.write(', '); + } + + Library lib = library.exported[i]; + if (package.libraries.contains(lib)) { + html.write('${lib.name}'); + } else { + html.write(lib.name); + } + } + html.endTag(); + } + + html.writeln('
'); + + html.startTag('dl', attributes: "class=dl-horizontal"); + + List variables = library.getVariables(); + List accessors = library.getAccessors(); + List functions = library.getFunctions(); + List typedefs = library.getTypedefs(); + List types = library.getTypes(); + + createToc(variables); + createToc(accessors); + createToc(functions); + createToc(typedefs); + createToc(types); + + html.endTag(); // dl + + printComments(library); + + generateElements(variables); + generateElements(accessors); + generateElements(functions); + generateElements(typedefs); + + types.forEach(generateClass); + + html.writeln('
'); + + html.endTag(); // div.span9 + + html.endTag(); // div.row + + html.endTag(); // div.container + + html.generateFooter(); + + html.end(); + + // write the file contents + f.writeAsStringSync(html.toString()); + } + + void createToc(List elements) { + if (!elements.isEmpty) { + html.tag('dt', contents: elements[0].typeName); + html.startTag('dd'); + for (ModelElement e in elements) { + html.writeln('${createIconFor(e)}${e.createLinkedSummary(helper)}
'); + } + html.endTag(); + } + } + + void generateClass(Class cls) { + + html.write(createAnchor(cls)); + html.writeln('
'); + html.startTag('h4'); + generateAnnotations(cls.getAnnotations()); + html.write(createIconFor(cls)); + if (cls.isAbstract) { + html.write('Abstract class ${cls.name}'); + } else { + html.write('Class ${cls.name}'); + } + if (cls.hasSupertype) { + html.write(' extends ${helper.createLinkedTypeName(cls.supertype)}'); + } + if (!cls.mixins.isEmpty) { + html.write(' with'); + for (int i = 0; i < cls.mixins.length; i++) { + if (i == 0) { + html.write(' '); + } else { + html.write(', '); + } + html.write(helper.createLinkedTypeName(cls.mixins[i])); + } + } + + if (!cls.interfaces.isEmpty) { + html.write(' implements'); + for (int i = 0; i < cls.interfaces.length; i++) { + if (i == 0) { + html.write(' '); + } else { + html.write(', '); + } + html.write(helper.createLinkedTypeName(cls.interfaces[i])); + } + } + + html.endTag(); + + html.startTag('dl', attributes: 'class=dl-horizontal'); + createToc(cls.getStaticFields()); + createToc(cls.getInstanceFields()); + createToc(cls.getAccessors()); + createToc(cls.getCtors()); + createToc(cls.getMethods()); + html.endTag(); + + printComments(cls); + + generateElements(cls.getStaticFields(), false); + generateElements(cls.getInstanceFields(), false); + generateElements(cls.getAccessors(), false); + generateElements(cls.getCtors(), false); + generateElements(cls.getMethods(), false); + } + + + void printComments(ModelElement e, [bool indent = true]) { + String comments = e.getDocumentation(); + if (comments != null) { + if (indent) { + html.startTag('div', attributes: "class=indent"); + } + html.tag('p', contents: cleanupDocs(e, comments)); + if (indent) { + html.endTag(); + } + } else { + if (indent) { + html.tag('div', attributes: "class=indent"); + } + } + } + + + void generateElements(List elements, [bool header = true]) { + if (!elements.isEmpty) { + html.tag('h4', contents: elements[0].typeName); + if (header) { + html.startTag('div', attributes: "class=indent"); + } + elements.forEach(generateElement); + if (header) { + html.endTag(); + } + } + } + + void generateElement(ModelElement f) { + html.startTag('b', newLine: false); + html.write('${createAnchor(f)}'); + generateAnnotations(f.getAnnotations()); + html.write(createIconFor(f)); + if (f is Method) { + html.write(generateOverrideIcon(f)); + } + html.write(f.createLinkedDescription(helper)); + html.endTag(); + printComments(f); + } + + void generateAnnotations(List annotations) { + if (!annotations.isEmpty) { + html.write(' '); + for (String a in annotations) { + // TODO: I don't believe we get back the right elements for const + // ctor annotations + html.writeln('@${a} '); + } + html.writeln('
'); + } + } + + String generateOverrideIcon(Method method) { + ModelElement o = method.getOverriddenElement(); + if (o == null) { + return ''; + } else if (!package.isDocumented(o)) { + return " "; + } else { + return "" " "; + } + } + + String getNameFor(ModelElement e) { + Class c = e.getEnclosingElement(); + // TODO: upscale this! handle ctors + String ext = (e.isExecutable) ? '()' : ''; + return '${c.name}.${htmlEscape(e.name)}${ext}'; + } + + String createAnchor(ModelElement e) { + Class c = e.getEnclosingElement(); + + if (c != null) { + return ''; + } else { + return ''; + } + } + + String createIconFor(ModelElement e) { + if (e.isPropertyAccessor) { + Accessor a = (e as Accessor); + if (a.isGetter) { + return ' '; + } else { + return ' '; + } + } else if (e is Class) { + return ' '; + } else if (e is Function) { + return ' '; + } else if (e.isPropertyInducer) { + return ' '; + } else if (e is Constructor) { + return ' '; + } else if (e.isExecutable) { + return ' '; + } else { + return ''; + } + } + + String cleanupDocs(ModelElement e, String docs) { + if (docs == null) { + return ''; + } + docs = htmlEscape(docs); + docs = stripComments(docs); + StringBuffer buf = new StringBuffer(); + + bool inCode = false; + bool inList = false; + for (String line in docs.split('\n')) { + if (inList && !line.startsWith("* ")) { + inList = false; + buf.write(''); + } + if (inCode && !(line.startsWith(' ') || line.trim().isEmpty)) { + inCode = false; + buf.write(''); + } else if (line.startsWith(' ') && !inCode) { + inCode = true; + buf.write('
');
+      } else if (line.trim().startsWith('* ') && !inList) {
+        inList = true;
+        buf.write('
    '); + } + if (inCode) { + if (line.startsWith(' ')) { + buf.write('${line.substring(4)}\n'); + } else { + buf.write('${line}\n'); + } + } else if (inList) { + buf.write('
  • ${_cleanupMarkdown(e, line.trim().substring(2))}
  • '); + } else if (line.trim().length == 0) { + buf.write('

    \n

    '); + } else { + buf.write('${_cleanupMarkdown(e, line)} '); + } + } + if (inCode) { + buf.write('

'); + } + return buf.toString().replaceAll('\n\n', '\n').trim(); + } + + String _cleanupMarkdown(ModelElement e, String line) { + line = ltrim(line); + if (line.startsWith("##")) { + line = line.substring(2); + if (line.endsWith("##")) { + line = line.substring(0, line.length - 2); + } + line = "
$line
"; + } else { + line = replaceAll(line, ['[:', ':]'], htmlEntity: 'code'); + line = replaceAll(line, ['`', '`'], htmlEntity: 'code'); + line = replaceAll(line, ['*', '*'], htmlEntity: 'i'); + line = replaceAll(line, ['__', '__'], htmlEntity: 'b'); + line = replaceAll(line, ['[', ']'], replaceFunction: (String ref) { + return _resolveCodeReference(e, ref); + }); + } + return line; + } + + String _resolveCodeReference(ModelElement e, String reference) { + ModelElement element = e.getChild(reference); + + if (element.isLocalElement) { + element = null; + } + if (element != null) { + return helper.createLinkedName(element, true); + } else { + //return "$reference"; + return "$reference"; + } + } + + +} + +String _getFileNameFor(Library library) { + return '${library.name}.html'; +} + + +class HtmlGeneratorHelper extends Helper { + + Package package; + + HtmlGeneratorHelper(this.package); + + String createLinkedName(ModelElement e, [bool appendParens = false]) { + if (e == null) { + return ''; + } + if (!package.isDocumented(e)) { + return htmlEscape(e.name); + } + if (e.name.startsWith('_')) { + return htmlEscape(e.name); + } + Class c = e.getEnclosingElement(); + if (c != null && c.name.startsWith('_')) { + return '${c.name}.${htmlEscape(e.name)}'; + } + if (c != null && e is Constructor) { + String name; + if (e.name.isEmpty) { + name = c.name; + } else { + name = '${c.name}.${htmlEscape(e.name)}'; + } + if (appendParens) { + return "${name}()"; + } else { + return "${name}"; + } + } else { + String append = ''; + + if (appendParens && (e is Method || e is Fnction)) { + append = '()'; + } + return "${htmlEscape(e.name)}$append"; + } + } + + String createHrefFor(ModelElement e) { + if (!package.isDocumented(e)) { + return ''; + } + Class c = e.getEnclosingElement(); + if (c != null) { + return '${_getFileNameFor(e.library)}#${c.name}.${escapeBrackets(e.name)}'; + } else { + return '${_getFileNameFor(e.library)}#${e.name}'; + } + } + + String printParams(List params) { + StringBuffer buf = new StringBuffer(); + + for (Parameter p in params) { + if (buf.length > 0) { + buf.write(', '); + } + if (p.type != null && p.type.name != null) { + buf.write(createLinkedTypeName(p.type)); + buf.write(' '); + } + buf.write(p.name); + } + return buf.toString(); + } + + String createLinkedTypeName(ElementType type) { + StringBuffer buf = new StringBuffer(); + + if (type.isParameterType) { + buf.write(type.element.name); + } else { + buf.write(createLinkedName(type.element)); + } + + if (type.isParameterizedType) { + if (!type.typeArguments.isEmpty) { + buf.write('<'); + for (int i = 0; i < type.typeArguments.length; i++) { + if (i > 0) { + buf.write(', '); + } + ElementType t = type.typeArguments[i]; + buf.write(createLinkedTypeName(t)); + } + buf.write('>'); + } + } + return buf.toString(); + } + + + String createLinkedReturnTypeName(ElementType type) { + if (type.returnElement == null) { + if (type.returnTypeName != null) { + return type.returnTypeName; + } else { + return ''; + } + } else { + return createLinkedTypeName(type.returnType); + } + } +} + + + diff --git a/lib/src/helpers.dart b/lib/src/helpers.dart deleted file mode 100644 index c1bb460879..0000000000 --- a/lib/src/helpers.dart +++ /dev/null @@ -1,415 +0,0 @@ -// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library dartdoc.helpers; - -import 'package:analyzer/src/generated/element.dart'; - -import 'model_utils.dart'; -import 'utils.dart'; - -class LibraryHelper { - LibraryElement library; - - LibraryHelper(this.library); - - List getVariables() { - List variables = []; - - variables.addAll(library.definingCompilationUnit.topLevelVariables); - for (CompilationUnitElement cu in library.parts) { - variables.addAll(cu.topLevelVariables); - } - - variables - ..removeWhere(isPrivate) - ..sort(elementCompare); - - return variables.map((e) => new VariableHelper(e)).toList(); - } - - List getAccessors() { - List accessors = []; - - accessors.addAll(library.definingCompilationUnit.accessors); - for (CompilationUnitElement cu in library.parts) { - accessors.addAll(cu.accessors); - } - - accessors - ..removeWhere(isPrivate) - ..sort(elementCompare); - accessors.removeWhere((e) => e.isSynthetic); - - return accessors.map((e) => new AccessorHelper(e)).toList(); - } - - List getTypedefs() { - List functions = []; - - functions.addAll(library.definingCompilationUnit.functionTypeAliases); - for (CompilationUnitElement cu in library.parts) { - functions.addAll(cu.functionTypeAliases); - } - - functions - ..removeWhere(isPrivate) - ..sort(elementCompare); - - return functions.map((e) => new TypedefHelper(e)).toList(); - } - - List getFunctions() { - List functions = []; - - functions.addAll(library.definingCompilationUnit.functions); - for (CompilationUnitElement cu in library.parts) { - functions.addAll(cu.functions); - } - - functions - ..removeWhere(isPrivate) - ..sort(elementCompare); - - return functions.map((e) => new FunctionHelper(e)).toList(); - } - - List getTypes() { - List types = []; - - types.addAll(library.definingCompilationUnit.types); - for (CompilationUnitElement cu in library.parts) { - types.addAll(cu.types); - } - - types - ..removeWhere(isPrivate) - ..sort(elementCompare); - - return types.map((e) => new ClassHelper(e)).toList(); - } -} - -abstract class ElementHelper { - Element element; - - ElementHelper(this.element); - - String get typeName; - - String createLinkedSummary(Generator generator) { - return generator.createLinkedName(element); - } - - String createLinkedDescription(Generator generator); -} - -class ClassHelper extends ElementHelper { - - ClassHelper(ClassElement element) : super(element); - - String get typeName => 'Classes'; - - ClassElement get _cls => element as ClassElement; - - String createLinkedDescription(Generator generator) { - return ''; - } - - List _getAllfields() { - return _cls.fields.toList() - ..removeWhere(isPrivate) - ..sort(elementCompare); - } - - List getStaticFields() { - List fields = _getAllfields()..removeWhere((e) => !isStatic(e)); - return fields.map((e) => new StaticFieldHelper(e)).toList(); - } - - List getInstanceFields() { - List fields = _getAllfields()..removeWhere(isStatic); - return fields.map((e) => new FieldHelper(e)).toList(); - } - - List getAccessors() { - List accessors = _cls.accessors.toList() - ..removeWhere(isPrivate) - ..sort(elementCompare); - accessors.removeWhere((e) => e.isSynthetic); - return accessors.map((e) => new AccessorHelper(e)).toList(); - } - - List getCtors() { - List c = _cls.constructors.toList() - ..removeWhere(isPrivate) - ..sort(elementCompare); - return c.map((e) => new ConstructorHelper(e)).toList(); - } - - List getMethods() { - List m = _cls.methods.toList() - ..removeWhere(isPrivate) - ..sort(elementCompare); - return m.map((e) => new MethodHelper(e)).toList(); - } -} - -abstract class PropertyInducingHelper extends ElementHelper { - PropertyInducingHelper(PropertyInducingElement element) : super(element); - - PropertyInducingElement get _var => (element as PropertyInducingElement); - - String createLinkedSummary(Generator generator) { - StringBuffer buf = new StringBuffer(); - - buf.write('${generator.createLinkedName(_var)}'); - - String type = generator.createLinkedName(_var.type == null ? null : _var.type.element); - - if (!type.isEmpty) { - buf.write(': $type'); - } - - return buf.toString(); - } - - String createLinkedDescription(Generator generator) { - StringBuffer buf = new StringBuffer(); - - if (_var.isStatic) { - buf.write('static '); - } - if (_var.isFinal) { - buf.write('final '); - } - if (_var.isConst) { - buf.write('const '); - } - - buf.write(generator.createLinkedName(_var.type == null ? null : _var.type.element)); - buf.write(' ${_var.name}'); - - // write out any constant value - Object value = getConstantValue(_var); - - if (value != null) { - if (value is String) { - String str = stringEscape(value, "'"); - buf.write(" = '${str}'"); - } else if (value is num) { - buf.write(" = ${value}"); - } - //NumberFormat.decimalPattern - } - - return buf.toString(); - } -} - -class VariableHelper extends PropertyInducingHelper { - VariableHelper(TopLevelVariableElement element) : super(element); - - String get typeName => 'Top-Level Variables'; -} - -class FieldHelper extends PropertyInducingHelper { - FieldHelper(FieldElement element) : super(element); - - String get typeName => 'Fields'; -} - -class StaticFieldHelper extends PropertyInducingHelper { - StaticFieldHelper(FieldElement element) : super(element); - - String get typeName => 'Static Fields'; -} - -class AccessorHelper extends ElementHelper { - AccessorHelper(PropertyAccessorElement element) : super(element); - - String get typeName => 'Getters and Setters'; - - PropertyAccessorElement get _acc => (element as PropertyAccessorElement); - - String createLinkedSummary(Generator generator) { - StringBuffer buf = new StringBuffer(); - - if (_acc.isGetter) { - buf.write(generator.createLinkedName(element)); - buf.write(': '); - buf.write(generator.createLinkedReturnTypeName(_acc.type)); - } else { - buf.write('${generator.createLinkedName(element)}(' '${generator.printParams(_acc.parameters)})'); - } - - return buf.toString(); - } - - String createLinkedDescription(Generator generator) { - StringBuffer buf = new StringBuffer(); - - if (_acc.isStatic) { - buf.write('static '); - } - - if (_acc.isGetter) { - buf.write('${generator.createLinkedReturnTypeName(_acc.type)} get ${_acc.name}'); - } else { - buf.write('set ${_acc.name}(${generator.printParams(_acc.parameters)})'); - } - - return buf.toString(); - } -} - -class FunctionHelper extends ElementHelper { - FunctionHelper(FunctionElement element) : super(element); - - String get typeName => 'Functions'; - - FunctionElement get _func => (element as FunctionElement); - - String createLinkedSummary(Generator generator) { - String retType = generator.createLinkedReturnTypeName(_func.type); - - return '${generator.createLinkedName(element)}' '(${generator.printParams(_func.parameters)})' '${retType.isEmpty ? '' : ': $retType'}'; - } - - String createLinkedDescription(Generator generator) { - StringBuffer buf = new StringBuffer(); - - if (_func.isStatic) { - buf.write('static '); - } - - buf.write(generator.createLinkedReturnTypeName(_func.type)); - buf.write(' ${_func.name}(${generator.printParams(_func.parameters)})'); - - return buf.toString(); - } -} - -class TypedefHelper extends ElementHelper { - TypedefHelper(FunctionTypeAliasElement element) : super(element); - - String get typeName => 'Typedefs'; - - FunctionTypeAliasElement get _typedef => (element as FunctionTypeAliasElement); - - String createLinkedSummary(Generator generator) { - // Comparator(T a, T b): int - StringBuffer buf = new StringBuffer(); - - buf.write(generator.createLinkedName(element)); - if (!_typedef.typeParameters.isEmpty) { - buf.write('<'); - for (int i = 0; i < _typedef.typeParameters.length; i++) { - if (i > 0) { - buf.write(', '); - } - buf.write(_typedef.typeParameters[i].name); - } - buf.write('>'); - } - buf.write('(${generator.printParams(_typedef.parameters)}): '); - buf.write(generator.createLinkedReturnTypeName(_typedef.type)); - - return buf.toString(); - } - - String createLinkedDescription(Generator generator) { - // typedef int Comparator(T a, T b) - - StringBuffer buf = new StringBuffer(); - - buf.write('typedef ${generator.createLinkedReturnTypeName(_typedef.type)} ${_typedef.name}'); - if (!_typedef.typeParameters.isEmpty) { - buf.write('<'); - for (int i = 0; i < _typedef.typeParameters.length; i++) { - if (i > 0) { - buf.write(', '); - } - buf.write(_typedef.typeParameters[i].name); - } - buf.write('>'); - } - buf.write('(${generator.printParams(_typedef.parameters)}): '); - - return buf.toString(); - } -} - -abstract class ExecutableHelper extends ElementHelper { - ExecutableHelper(ExecutableElement element) : super(element); - - ExecutableElement get _ex => (element as ExecutableElement); - - String createLinkedSummary(Generator generator) { - String retType = generator.createLinkedReturnTypeName(_ex.type); - - return '${generator.createLinkedName(element)}' '(${generator.printParams(_ex.parameters)})' '${retType.isEmpty ? '' : ': $retType'}'; - } - - String createLinkedDescription(Generator generator) { - StringBuffer buf = new StringBuffer(); - - if (_ex.isStatic) { - buf.write('static '); - } - - buf.write(generator.createLinkedReturnTypeName(_ex.type)); - buf.write(' ${_ex.name}(${generator.printParams(_ex.parameters)})'); - - return buf.toString(); - } -} - -class ConstructorHelper extends ExecutableHelper { - ConstructorHelper(ConstructorElement element) : super(element); - - String get typeName => 'Constructors'; - - ConstructorElement get _ctor => (element as ConstructorElement); - - String createLinkedSummary(Generator generator) { - return '${generator.createLinkedName(element)}' '(${generator.printParams(_ex.parameters)})'; - } - - String createLinkedDescription(Generator generator) { - StringBuffer buf = new StringBuffer(); - - if (_ex.isStatic) { - buf.write('static '); - } - if (_ctor.isFactory) { - buf.write('factory '); - } - - buf.write('${_ctor.type.returnType.name}${_ctor.name.isEmpty?'':'.'}' '${_ctor.name}(${generator.printParams(_ex.parameters)})'); - - return buf.toString(); - } -} - -class MethodHelper extends ExecutableHelper { - MethodHelper(MethodElement element) : super(element); - - String get typeName => 'Methods'; -} - -bool isStatic(PropertyInducingElement e) => e.isStatic; - -bool isPrivate(Element e) => e.name.startsWith('_'); - -int elementCompare(Element a, Element b) => a.name.compareTo(b.name); - -abstract class Generator { - String createLinkedName(Element e, [bool appendParens = false]); - String createLinkedReturnTypeName(FunctionType type); - String createLinkedTypeName(DartType type); - String printParams(List params); - String createHrefFor(Element e); - bool isDocumented(Element e); -} diff --git a/lib/src/html_gen.dart b/lib/src/html_gen.dart index ff2a0d1bb6..1b3aadb69c 100644 --- a/lib/src/html_gen.dart +++ b/lib/src/html_gen.dart @@ -4,41 +4,48 @@ library html_gen; -class HtmlGenerator { +class HtmlHelper { StringBuffer buffer = new StringBuffer(); bool startOfLine = true; List tags = []; List indents = []; String indent = ''; - HtmlGenerator() { + HtmlHelper() { writeln(''); writeln(); writeln(''); writeln(); } + void generateHeader() { + // header + startTag('header'); + endTag(); + } + + void generateFooter() { + // footer + startTag('footer'); + endTag(); + } + + void start({String title, String cssRef}) { startTag('html', newLine: false); writeln(); startTag('head'); - writeln(''); writeln(''); - if (title != null) { writeln('${title}'); } - if (cssRef != null) { writeln(''); } - // head endTag(); - writeln(); - startTag('body', newLine: false); writeln(); } @@ -92,7 +99,6 @@ class HtmlGenerator { void end() { // body endTag(); - // html endTag(); } diff --git a/lib/src/utils.dart b/lib/src/html_utils.dart similarity index 90% rename from lib/src/utils.dart rename to lib/src/html_utils.dart index bb889b77ad..dc1a01d88c 100644 --- a/lib/src/utils.dart +++ b/lib/src/html_utils.dart @@ -2,7 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -library dartdoc.utils; +library dartdoc.html_utils; String htmlEscape(String text) { return text.replaceAll('&', '&').replaceAll('>', '>').replaceAll('<', '<'); @@ -116,18 +116,18 @@ String _processMarkdown(CodeResolver resolver, String line) { } line = "
$line
"; } else { - line = _replaceAll(line, ['[:', ':]'], htmlEntity: 'code'); - line = _replaceAll(line, ['`', '`'], htmlEntity: 'code'); - line = _replaceAll(line, ['*', '*'], htmlEntity: 'i'); - line = _replaceAll(line, ['__', '__'], htmlEntity: 'b'); - line = _replaceAll(line, ['[', ']'], replaceFunction: (String ref) { + line = replaceAll(line, ['[:', ':]'], htmlEntity: 'code'); + line = replaceAll(line, ['`', '`'], htmlEntity: 'code'); + line = replaceAll(line, ['*', '*'], htmlEntity: 'i'); + line = replaceAll(line, ['__', '__'], htmlEntity: 'b'); + line = replaceAll(line, ['[', ']'], replaceFunction: (String ref) { return resolver.resolveCodeReference(ref); }); } return line; } -String _replaceAll(String str, List matchChars, {String htmlEntity, var replaceFunction}) { +String replaceAll(String str, List matchChars, {String htmlEntity, var replaceFunction}) { int lastWritten = 0; int index = str.indexOf(matchChars[0]); StringBuffer buf = new StringBuffer(); @@ -155,3 +155,5 @@ String _replaceAll(String str, List matchChars, {String htmlEntity, var } return buf.toString(); } + + diff --git a/lib/src/model.dart b/lib/src/model.dart new file mode 100644 index 0000000000..dd106f8403 --- /dev/null +++ b/lib/src/model.dart @@ -0,0 +1,583 @@ +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + + +/// The models used to represent Dart code +library dartdoc.models; + +import 'package:analyzer/src/generated/element.dart'; + +import 'html_utils.dart'; +import 'model_utils.dart'; +import 'package_utils.dart'; + + +abstract class ModelElement { + + Element element; + + Library library; + + ModelElement(this.element, this.library); + + factory ModelElement.from(Element e, Library library) { + if (e is ClassElement) { + return new Class(e, library); + } + if (e is FunctionElement) { + return new Fnction(e, library); + } + if (e is FunctionTypeAliasElement) { + return new Typedef(e, library); + } + if (e is FieldElement) { + return new Field(e, library); + } + if (e is ConstructorElement) { + return new Constructor(e, library); + } + if (e is MethodElement) { + return new Method(e, library); + } + if (e is PropertyAccessorElement) { + return new Accessor(e, library); + } + if (e is TopLevelVariableElement) { + return new Variable(e, library); + } + } + + String getDocumentation() { + if (element == null) { + return null; + } + + String comments = element.computeDocumentationComment(); + + if (comments != null) { + return comments; + } + + if (canOverride()) { + if (getOverriddenElement() != null) { + return getOverriddenElement().getDocumentation(); + } + } + return null; + } + + ModelElement getChild(String reference) { + Element e = (element as ElementImpl).getChild(reference); + if (e is LocalElement /*|| e is TypeVariableElement*/) { + return null; + } + return new ModelElement.from(e, library); + } + + List getAnnotations() { + List a = element.metadata; + if (a.isNotEmpty) { + return a.map((f) => f.element.name).toList(); + } + return []; + } + + bool canOverride() => element is ClassMemberElement; + + ModelElement getOverriddenElement() => null; + + String get typeName => 'element'; + + String get name => element.name; + + bool get isExecutable => element is ExecutableElement; + + bool get isPropertyInducer => element is PropertyInducingElement; + + bool get isPropertyAccessor => element is PropertyAccessorElement; + + bool get isLocalElement => element is LocalElement; + + bool get isStatic { + if (isPropertyInducer) { + return (element as PropertyInducingElement).isStatic; + } + return false; + } + + bool get isFinal => false; + + bool get isConst => false; + + Class getEnclosingElement() { + if (element is ClassMemberElement) { + return new Class(element.enclosingElement, library); + } else { + return null; + } + } + + String createLinkedSummary(Helper generator) { + if (isExecutable) { + ExecutableElement ex = (element as ExecutableElement); + String retType = generator.createLinkedReturnTypeName(new ElementType(ex.type, library)); + + return '${generator.createLinkedName(this)}' + '(${generator.printParams(ex.parameters.map((f)=> + new Parameter(f, library)))})' + '${retType.isEmpty ? '' : ': $retType'}'; + } + if (isPropertyInducer) { + PropertyInducingElement pe = (element as PropertyInducingElement); + StringBuffer buf = new StringBuffer(); + buf.write('${generator.createLinkedName(this)}'); + String type = generator.createLinkedName(pe.type == null ? null : new ModelElement.from(pe.type.element, library)); + if (!type.isEmpty) { + buf.write(': $type'); + } + return buf.toString(); + } + return generator.createLinkedName(this); + } + + String createLinkedDescription(Helper generator) { + if (isExecutable && !(element is ConstructorElement)) { + ExecutableElement e = (element as ExecutableElement); + StringBuffer buf = new StringBuffer(); + + if (e.isStatic) { + buf.write('static '); + } + + buf.write(generator.createLinkedReturnTypeName(new ElementType(e.type, library))); + buf.write(' ${e.name}(${generator.printParams(e.parameters.map((f)=> new Parameter(f, library)).toList())})'); + return buf.toString(); + } + if (isPropertyInducer) { + PropertyInducingElement e = (element as PropertyInducingElement); + StringBuffer buf = new StringBuffer(); + if (e.isStatic) { + buf.write('static '); + } + if (e.isFinal) { + buf.write('final '); + } + if (e.isConst) { + buf.write('const '); + } + + buf.write(generator.createLinkedName(e.type == null ? null : new ModelElement.from(e.type.element, library))); + buf.write(' ${e.name}'); + + // write out any constant value + Object value = getConstantValue(e); + + if (value != null) { + if (value is String) { + String str = stringEscape(value, "'"); + buf.write(" = '${str}'"); + } else if (value is num) { + buf.write(" = ${value}"); + } + //NumberFormat.decimalPattern + } + return buf.toString(); + } + return null; + } +} + +class Package { + + String _rootDirPath; + + List _libraries = []; + + String get name => getPackageName(_rootDirPath); + + String get version => getPackageVersion(_rootDirPath); + + String get description => getPackageDescription(_rootDirPath); + + List get libraries => _libraries; + + Package(Iterable libraryElements, this._rootDirPath) { + libraryElements.forEach((element) { + _libraries.add(new Library(element)); + }); + } + + bool isDocumented(ModelElement e) { + if (e is Library) { + return _libraries.contains(e); + } + return _libraries.contains(e.library); + } +} + +class Library extends ModelElement { + + LibraryElement get _library => (element as LibraryElement); + + Library(LibraryElement element) : super(element, null); + + List get exported => _library.exportedLibraries.map((lib) => new Library(lib)).toList(); + + List getVariables() { + List elements = []; + elements.addAll(_library.definingCompilationUnit.topLevelVariables); + for (CompilationUnitElement cu in _library.parts) { + elements.addAll(cu.topLevelVariables); + } + elements + ..removeWhere(isPrivate) + ..sort(elementCompare); + return elements.map((e) => new Variable(e, this)).toList(); + } + + List getAccessors() { + List elements = []; + elements.addAll(_library.definingCompilationUnit.accessors); + for (CompilationUnitElement cu in _library.parts) { + elements.addAll(cu.accessors); + } + elements + ..removeWhere(isPrivate) + ..sort(elementCompare); + elements.removeWhere((e) => e.isSynthetic); + return elements.map((e) => new Accessor(e, this)).toList(); + } + + List getTypedefs() { + List elements = []; + elements.addAll(_library.definingCompilationUnit.functionTypeAliases); + for (CompilationUnitElement cu in _library.parts) { + elements.addAll(cu.functionTypeAliases); + } + elements + ..removeWhere(isPrivate) + ..sort(elementCompare); + return elements.map((e) => new Typedef(e, this)).toList(); + } + + List getFunctions() { + List elements = []; + elements.addAll(_library.definingCompilationUnit.functions); + for (CompilationUnitElement cu in _library.parts) { + elements.addAll(cu.functions); + } + elements + ..removeWhere(isPrivate) + ..sort(elementCompare); + return elements.map((e) => new Fnction(e, this)).toList(); + } + + List getTypes() { + List types = []; + types.addAll(_library.definingCompilationUnit.types); + for (CompilationUnitElement cu in _library.parts) { + types.addAll(cu.types); + } + types + ..removeWhere(isPrivate) + ..sort(elementCompare); + return types.map((e) => new Class(e, this)).toList(); + } +} + +class Class extends ModelElement { + + ClassElement get _cls => (element as ClassElement); + + String get typeName => 'Classes'; + + Class(ClassElement element, Library library) : super(element, library); + + bool get isAbstract => _cls.isAbstract; + + bool get hasSupertype => _cls.supertype != null && _cls.supertype.element.supertype != null; + + ElementType get supertype => new ElementType(_cls.supertype, library); + + List get mixins => _cls.mixins.map((f) => new ElementType(f, library)).toList(); + + List get interfaces => _cls.interfaces.map((f) => new ElementType(f, library)).toList(); + + List _getAllfields() { + List elements = _cls.fields.toList() + ..removeWhere(isPrivate) + ..sort(elementCompare); + return elements.map((e) => new Field(e, library)).toList(); + } + + List getStaticFields() => _getAllfields()..removeWhere((f) => !f.isStatic); + + List getInstanceFields() => _getAllfields()..removeWhere((f) => f.isStatic); + + List getAccessors() { + List accessors = _cls.accessors.toList() + ..removeWhere(isPrivate) + ..sort(elementCompare); + accessors.removeWhere((e) => e.isSynthetic); + return accessors.map((e) => new Accessor(e, library)).toList(); + } + + List getCtors() { + List c = _cls.constructors.toList() + ..removeWhere(isPrivate) + ..sort(elementCompare); + return c.map((e) => new Constructor(e, library)).toList(); + } + + List getMethods() { + List m = _cls.methods.toList() + ..removeWhere(isPrivate) + ..sort(elementCompare); + return m.map((e) => new Method(e, library)).toList(); + } + + String createLinkedDescription(Helper generator) { + return ''; + } +} + + +class Fnction extends ModelElement { + + Fnction(FunctionElement element, Library library) : super(element, library); + + FunctionElement get _func => (element as FunctionElement); + + String get typeName => 'Functions'; + + String createLinkedSummary(Helper generator) { + String retType = generator.createLinkedReturnTypeName(new ElementType(_func.type, library)); + + return '${generator.createLinkedName(this)}' + '(${generator.printParams(_func.parameters.map((f)=> new Parameter(f, library)))})' + '${retType.isEmpty ? '' : ': $retType'}'; + } + + String createLinkedDescription(Helper generator) { + StringBuffer buf = new StringBuffer(); + if (_func.isStatic) { + buf.write('static '); + } + buf.write(generator.createLinkedReturnTypeName(new ElementType(_func.type, library))); + buf.write(' ${_func.name}(${generator.printParams(_func.parameters.map((f)=> new Parameter(f, library)))})'); + return buf.toString(); + } +} + + +class Typedef extends ModelElement { + + FunctionTypeAliasElement get _typedef => (element as FunctionTypeAliasElement); + + Typedef(FunctionTypeAliasElement element, Library library) : super(element, library); + + String get typeName => 'Typedefs'; + + String createLinkedSummary(Helper generator) { + // Comparator(T a, T b): int + StringBuffer buf = new StringBuffer(); + buf.write(generator.createLinkedName(this)); + if (!_typedef.typeParameters.isEmpty) { + buf.write('<'); + for (int i = 0; i < _typedef.typeParameters.length; i++) { + if (i > 0) { + buf.write(', '); + } + buf.write(_typedef.typeParameters[i].name); + } + buf.write('>'); + } + buf.write('(${generator.printParams(_typedef.parameters.map((f)=> new Parameter(f, library)))}): '); + buf.write(generator.createLinkedReturnTypeName(new ElementType(_typedef.type, library))); + return buf.toString(); + } + + String createLinkedDescription(Helper generator) { + // typedef int Comparator(T a, T b) + + StringBuffer buf = new StringBuffer(); + buf.write('typedef ${generator.createLinkedReturnTypeName(new ElementType(_typedef.type, library))} ${_typedef.name}'); + if (!_typedef.typeParameters.isEmpty) { + buf.write('<'); + for (int i = 0; i < _typedef.typeParameters.length; i++) { + if (i > 0) { + buf.write(', '); + } + buf.write(_typedef.typeParameters[i].name); + } + buf.write('>'); + } + buf.write('(${generator.printParams(_typedef.parameters.map((f)=> new Parameter(f, library)))}): '); + return buf.toString(); + } + +} + +class Field extends ModelElement { + + FieldElement get _field => (element as FieldElement); + + Field(FieldElement element, Library library) : super(element, library); + + bool get isFinal => _field.isFinal; + + bool get isConst => _field.isConst; + + String get typeName => 'Fields'; +} + +class Constructor extends ModelElement { + + ConstructorElement get _constructor => (element as ConstructorElement); + + Constructor(ConstructorElement element, Library library) : super(element, library); + + String get typeName => 'Constructors'; + + String createLinkedSummary(Helper generator) { + return '${generator.createLinkedName(this)}' '(${generator.printParams(_constructor.parameters.map((f) => new Parameter(f, library)).toList())})'; + } + + String createLinkedDescription(Helper generator) { + StringBuffer buf = new StringBuffer(); + if (_constructor.isStatic) { + buf.write('static '); + } + if (_constructor.isFactory) { + buf.write('factory '); + } + buf.write('${_constructor.type.returnType.name}${_constructor.name.isEmpty?'':'.'}' + '${_constructor.name}' + '(${generator.printParams( + _constructor.parameters.map((f)=> new Parameter(f, library)))})'); + return buf.toString(); + } +} + + +class Method extends ModelElement { + // MethodElement get _method => (element as MethodElement); + + Method(MethodElement element, Library library) : super(element, library); + + Method getOverriddenElement() { + ClassElement parent = element.enclosingElement; + for (InterfaceType t in getAllSupertypes(parent)) { + if (t.getMethod(element.name) != null) { + return new Method(t.getMethod(element.name), library); + } + } + return null; + } + + String get typeName => 'Methods'; +} + +class Accessor extends ModelElement { + + PropertyAccessorElement get _accessor => (element as PropertyAccessorElement); + + Accessor(PropertyAccessorElement element, Library library) : super(element, library); + + String get typeName => 'Getters and Setters'; + + bool get isGetter => _accessor.isGetter; + + String createLinkedSummary(Helper generator) { + StringBuffer buf = new StringBuffer(); + + if (_accessor.isGetter) { + buf.write(generator.createLinkedName(this)); + buf.write(': '); + buf.write(generator.createLinkedReturnTypeName( + new ElementType(_accessor.type, + new ModelElement.from(_accessor.type.element, library)))); + } else { + buf.write('${generator.createLinkedName(this)}(' + '${generator.printParams(_accessor.parameters.map((f)=> + new Parameter(f,library)))})'); + } + return buf.toString(); + } + + String createLinkedDescription(Helper generator) { + StringBuffer buf = new StringBuffer(); + if (_accessor.isStatic) { + buf.write('static '); + } + if (_accessor.isGetter) { + buf.write('${generator.createLinkedReturnTypeName(new ElementType(_accessor.type, new ModelElement.from(_accessor.type.element, library)))} get ${_accessor.name}'); + } else { + buf.write('set ${_accessor.name}(${generator.printParams(_accessor.parameters.map((f)=> new Parameter(f,library)))})'); + } + return buf.toString(); + } + +} + +class Variable extends ModelElement { + + TopLevelVariableElement get _variable => (element as TopLevelVariableElement); + + Variable(TopLevelVariableElement element, Library library) : super(element, library); + + String get typeName => 'Top-Level Variables'; + + bool get isFinal => _variable.isFinal; + + bool get isConst => _variable.isConst; +} + +class Parameter extends ModelElement { + + Parameter(ParameterElement element, Library library) : super(element, library); + + ParameterElement get _parameter => (element as ParameterElement); + + ElementType get type => new ElementType(_parameter.type, library); + +} + +class ElementType { + DartType _type; + Library library; + + ElementType(this._type, this.library); + + bool get isParameterType => (_type is TypeParameterType); + + ModelElement get element => new ModelElement.from(_type.element, library); + + String get name => _type.name; + + bool get isParameterizedType => (_type is ParameterizedType); + + String get returnTypeName => (_type as FunctionType).returnType.name; + + ElementType get returnType => new ElementType((_type as FunctionType).returnType, library); + + ModelElement get returnElement { + Element e = (_type as FunctionType).returnType.element; + if (e == null) { + return null; + } + return (new ModelElement.from(e, element.library)); + } + List get typeArguments => (_type as ParameterizedType).typeArguments.map((f) => new ElementType(f, library)).toList(); +} + + +abstract class Helper { + String createLinkedName(ModelElement e, [bool appendParens = false]); + String createLinkedReturnTypeName(ElementType type); + String createLinkedTypeName(ElementType type); + String printParams(List params); + String createHrefFor(ModelElement e); +} + diff --git a/lib/src/model_utils.dart b/lib/src/model_utils.dart index 7f7169f69a..1eda179f98 100644 --- a/lib/src/model_utils.dart +++ b/lib/src/model_utils.dart @@ -7,37 +7,6 @@ library model_utils; import 'package:analyzer/src/generated/element.dart'; import 'package:analyzer/src/generated/constant.dart'; -String getDocumentationFor(Element e) { - if (e == null) { - return null; - } - - String comments = e.computeDocumentationComment(); - - if (comments != null) { - return comments; - } - - if (canOverride(e)) { - return getDocumentationFor(getOverriddenElement(e)); - } else { - return null; - } -} - -String getFileNameFor(LibraryElement library) { - return '${library.name}.html'; -} - -Element getOverriddenElement(Element element) { - if (element is MethodElement) { - return getOverriddenElementMethod(element); - } else { - // TODO: ctors, fields, accessors - - - return null; - } -} Object getConstantValue(PropertyInducingElement element) { if (element is ConstFieldElementImpl) { @@ -59,25 +28,9 @@ Object _valueFor(EvaluationResultImpl result) { } } -MethodElement getOverriddenElementMethod(MethodElement element) { - ClassElement parent = element.enclosingElement; - for (InterfaceType t in getAllSupertypes(parent)) { - if (t.getMethod(element.name) != null) { - return t.getMethod(element.name); - } - } - return null; -} - -bool canOverride(Element e) => e is ClassMemberElement; +int elementCompare(Element a, Element b) => a.name.compareTo(b.name); -ClassElement getEnclosingElement(Element e) { - if (e is ClassMemberElement) { - return e.enclosingElement; - } else { - return null; - } -} +bool isPrivate(Element e) => e.name.startsWith('_'); List getAllSupertypes(ClassElement c) { InterfaceType t = c.type;