| Index: pkg/docgen/lib/docgen.dart
|
| diff --git a/pkg/docgen/bin/docgen.dart b/pkg/docgen/lib/docgen.dart
|
| similarity index 51%
|
| copy from pkg/docgen/bin/docgen.dart
|
| copy to pkg/docgen/lib/docgen.dart
|
| index 308df289271e71bab2ec5e94b542b2fccffffff0..49d659bf06488434e3a0ea94ada16df71200d2c7 100644
|
| --- a/pkg/docgen/bin/docgen.dart
|
| +++ b/pkg/docgen/lib/docgen.dart
|
| @@ -3,51 +3,76 @@
|
| // BSD-style license that can be found in the LICENSE file.
|
|
|
| /**
|
| - * The docgen tool takes in a library as input and produces documentation
|
| - * for the library as well as all libraries it imports and uses. The tool can
|
| - * be run by passing in the path to a .dart file like this:
|
| + * **docgen** is a tool for creating machine readable representations of Dart
|
| + * code metadata, including: classes, members, comments and annotations.
|
| + *
|
| + * docgen is run on a `.dart` file or a directory containing `.dart` files.
|
| + *
|
| + * $ dart docgen.dart [OPTIONS] [FILE/DIR]
|
| *
|
| - * ./dart docgen.dart path/to/file.dart
|
| - *
|
| - * This outputs information about all classes, variables, functions, and
|
| - * methods defined in the library and its imported libraries.
|
| + * This creates files called `docs/<library_name>.yaml` in your current
|
| + * working directory.
|
| */
|
| library docgen;
|
|
|
| -// TODO(tmandel): Use 'package:' references for imports with relative paths.
|
| import 'dart:io';
|
| import 'dart:json';
|
| import 'dart:async';
|
| -import '../lib/dart2yaml.dart';
|
| -import '../lib/src/dart2js_mirrors.dart';
|
| +
|
| +import 'package:args/args.dart';
|
| +import 'package:logging/logging.dart';
|
| import 'package:markdown/markdown.dart' as markdown;
|
| -import '../../args/lib/args.dart';
|
| +
|
| +import 'dart2yaml.dart';
|
| +import '../../../sdk/lib/_internal/compiler/compiler.dart' as api;
|
| +import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart';
|
| +import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart'
|
| + as dart2js;
|
| import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
|
| import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
|
| +import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider.dart';
|
|
|
| -/**
|
| - * Entry function to create YAML documentation from Dart files.
|
| - */
|
| -void main() {
|
| - // TODO(tmandel): Use args library once flags are clear.
|
| - Options opts = new Options();
|
| - Docgen docgen = new Docgen();
|
| -
|
| - if (opts.arguments.length > 0) {
|
| - List<Path> libraries = [new Path(opts.arguments[0])];
|
| - Path sdkDirectory = new Path("../../../sdk/");
|
| - var workingMirrors = analyze(libraries, sdkDirectory,
|
| - options: ['--preserve-comments', '--categories=Client,Server']);
|
| - workingMirrors.then( (MirrorSystem mirrorSystem) {
|
| - var mirrors = mirrorSystem.libraries.values;
|
| - if (mirrors.isEmpty) {
|
| - print("no LibraryMirrors");
|
| - } else {
|
| - docgen.libraries = mirrors;
|
| - docgen.documentLibraries();
|
| - }
|
| - });
|
| +var logger = new Logger("Docgen");
|
| +
|
| +/// Counter used to provide unique IDs for each distinct item.
|
| +int _nextID = 0;
|
| +
|
| +int get nextID => _nextID++;
|
| +
|
| +const String usage = "Usage: dart docgen.dart [OPTIONS] [fooDir/barFile]";
|
| +
|
| +List<Path> listLibraries(List<String> args) {
|
| + if (args.length != 1) {
|
| + throw new UnsupportedError(usage);
|
| }
|
| + var libraries = new List<Path>();
|
| + var type = FileSystemEntity.typeSync(args[0]);
|
| +
|
| + if (type == FileSystemEntityType.NOT_FOUND) {
|
| + throw new UnsupportedError("File does not exist. $usage");
|
| + } else if (type == FileSystemEntityType.LINK) {
|
| + libraries.addAll(listLibrariesFromDir(new Link(args[0]).targetSync()));
|
| + } else if (type == FileSystemEntityType.FILE) {
|
| + libraries.add(new Path(args[0]));
|
| + logger.info("Added to libraries: ${libraries.last.toString()}");
|
| + } else if (type == FileSystemEntityType.DIRECTORY) {
|
| + libraries.addAll(listLibrariesFromDir(args[0]));
|
| + }
|
| + return libraries;
|
| +}
|
| +
|
| +List<Path> listLibrariesFromDir(String path) {
|
| + var libraries = new List<Path>();
|
| + new Directory(path).listSync(recursive: true,
|
| + followLinks: true).forEach((file) {
|
| + if (new Path(file.path).extension == "dart") {
|
| + if (!file.path.contains("/packages/")) {
|
| + libraries.add(new Path(file.path));
|
| + logger.info("Added to libraries: ${libraries.last.toString()}");
|
| + }
|
| + }
|
| + });
|
| + return libraries;
|
| }
|
|
|
| /**
|
| @@ -58,9 +83,6 @@ class Docgen {
|
| /// Libraries to be documented.
|
| List<LibraryMirror> _libraries;
|
|
|
| - /// Saves list of libraries for Docgen object.
|
| - void set libraries(value) => _libraries = value;
|
| -
|
| /// Current library being documented to be used for comment links.
|
| LibraryMirror _currentLibrary;
|
|
|
| @@ -70,39 +92,120 @@ class Docgen {
|
| /// Current member being documented to be used for comment links.
|
| MemberMirror _currentMember;
|
|
|
| - /// Should the output file type be JSON?
|
| - // TODO(tmandel): Add flag to allow for output to JSON.
|
| - bool outputToJson = false;
|
| -
|
| /// Resolves reference links
|
| markdown.Resolver linkResolver;
|
|
|
| + bool outputToYaml;
|
| + bool outputToJson;
|
| + bool includePrivate;
|
| + /// State for whether or not the SDK libraries should also be outputted.
|
| + bool includeSdk;
|
| +
|
| /**
|
| * Docgen constructor initializes the link resolver for markdown parsing.
|
| + * Also initializes the command line arguments.
|
| */
|
| - Docgen() {
|
| + Docgen(ArgResults argResults) {
|
| + if (argResults["output-format"] == null) {
|
| + outputToYaml =
|
| + (argResults["yaml"] == false && argResults["json"] == false) ?
|
| + true : argResults["yaml"];
|
| + } else {
|
| + if ((argResults["output-format"] == "yaml" &&
|
| + argResults["json"] == true) ||
|
| + (argResults["output-format"] == "json" &&
|
| + argResults["yaml"] == true)) {
|
| + throw new UnsupportedError("Cannot have contradictory output flags.");
|
| + }
|
| + outputToYaml = argResults["output-format"] == "yaml" ? true : false;
|
| + }
|
| + outputToJson = !outputToYaml;
|
| + includePrivate = argResults["include-private"];
|
| + includeSdk = argResults["include-sdk"];
|
| +
|
| this.linkResolver = (name) =>
|
| fixReference(name, _currentLibrary, _currentClass, _currentMember);
|
| }
|
|
|
| /**
|
| + * Analyzes set of libraries by getting a mirror system and triggers the
|
| + * documentation of the libraries.
|
| + */
|
| + void analyze(List<Path> libraries) {
|
| + // DART_SDK should be set to the root of the SDK library.
|
| + var sdkRoot = Platform.environment["DART_SDK"];
|
| + if (sdkRoot != null) {
|
| + logger.info("Using DART_SDK to find SDK at $sdkRoot");
|
| + sdkRoot = new Path(sdkRoot);
|
| + } else {
|
| + // If DART_SDK is not defined in the environment,
|
| + // assuming the dart executable is from the Dart SDK folder inside bin.
|
| + sdkRoot = new Path(new Options().executable).directoryPath
|
| + .directoryPath;
|
| + logger.info("SDK Root: ${sdkRoot.toString()}");
|
| + }
|
| +
|
| + Path packageDir = libraries.last.directoryPath.append("packages");
|
| + logger.info("Package Root: ${packageDir.toString()}");
|
| + getMirrorSystem(libraries, sdkRoot,
|
| + packageRoot: packageDir).then((MirrorSystem mirrorSystem) {
|
| + if (mirrorSystem.libraries.values.isEmpty) {
|
| + throw new UnsupportedError("No Library Mirrors.");
|
| + }
|
| + this.libraries = mirrorSystem.libraries.values;
|
| + documentLibraries();
|
| + });
|
| + }
|
| +
|
| + /**
|
| + * Analyzes set of libraries and provides a mirror system which can be used
|
| + * for static inspection of the source code.
|
| + */
|
| + Future<MirrorSystem> getMirrorSystem(List<Path> libraries,
|
| + Path libraryRoot, {Path packageRoot}) {
|
| + SourceFileProvider provider = new SourceFileProvider();
|
| + api.DiagnosticHandler diagnosticHandler =
|
| + new FormattingDiagnosticHandler(provider).diagnosticHandler;
|
| + Uri libraryUri = currentDirectory.resolve(appendSlash('$libraryRoot'));
|
| + Uri packageUri = null;
|
| + if (packageRoot != null) {
|
| + packageUri = currentDirectory.resolve(appendSlash('$packageRoot'));
|
| + }
|
| + List<Uri> librariesUri = <Uri>[];
|
| + libraries.forEach((library) {
|
| + librariesUri.add(currentDirectory.resolve(library.toString()));
|
| + });
|
| + return dart2js.analyze(librariesUri, libraryUri, packageUri,
|
| + provider.readStringFromUri, diagnosticHandler,
|
| + ['--preserve-comments', '--categories=Client,Server']);
|
| + }
|
| +
|
| + /**
|
| * Creates documentation for filtered libraries.
|
| */
|
| void documentLibraries() {
|
| - //TODO(tmandel): Filter libraries and determine output type using flags.
|
| _libraries.forEach((library) {
|
| - _currentLibrary = library;
|
| - var result = new Library(library.qualifiedName, _getComment(library),
|
| - _getVariables(library.variables), _getMethods(library.functions),
|
| - _getClasses(library.classes));
|
| - if (outputToJson) {
|
| - _writeToFile(stringify(result.toMap()), "${result.name}.json");
|
| - } else {
|
| - _writeToFile(getYamlString(result.toMap()), "${result.name}.yaml");
|
| - }
|
| + // Files belonging to the SDK have a uri that begins with "dart:".
|
| + if (includeSdk || !library.uri.toString().startsWith("dart:")) {
|
| + _currentLibrary = library;
|
| + var result = new Library(library.qualifiedName, _getComment(library),
|
| + _getVariables(library.variables), _getMethods(library.functions),
|
| + _getClasses(library.classes), nextID);
|
| + if (outputToJson) {
|
| + _writeToFile(stringify(result.toMap()), "${result.name}.json");
|
| + }
|
| + if (outputToYaml) {
|
| + _writeToFile(getYamlString(result.toMap()), "${result.name}.yaml");
|
| + }
|
| + }
|
| });
|
| }
|
|
|
| + /// Saves list of libraries for Docgen object.
|
| + void set libraries(value){
|
| + _libraries = value;
|
| + }
|
| +
|
| /**
|
| * Returns any documentation comments associated with a mirror with
|
| * simple markdown converted to html.
|
| @@ -121,8 +224,10 @@ class Docgen {
|
| }
|
| }
|
| });
|
| - return commentText == null ? "" :
|
| - markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver);
|
| + commentText = commentText == null ? "" :
|
| + markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver)
|
| + .replaceAll("\n", "");
|
| + return commentText;
|
| }
|
|
|
| /**
|
| @@ -141,9 +246,12 @@ class Docgen {
|
| Map<String, Variable> _getVariables(Map<String, VariableMirror> mirrorMap) {
|
| var data = {};
|
| mirrorMap.forEach((String mirrorName, VariableMirror mirror) {
|
| - _currentMember = mirror;
|
| - data[mirrorName] = new Variable(mirrorName, mirror.isFinal,
|
| - mirror.isStatic, mirror.type.toString(), _getComment(mirror));
|
| + if (includePrivate || !mirror.isPrivate) {
|
| + _currentMember = mirror;
|
| + data[mirrorName] = new Variable(mirrorName, mirror.isFinal,
|
| + mirror.isStatic, mirror.type.toString(), _getComment(mirror),
|
| + nextID);
|
| + }
|
| });
|
| return data;
|
| }
|
| @@ -154,11 +262,13 @@ class Docgen {
|
| Map<String, Method> _getMethods(Map<String, MethodMirror> mirrorMap) {
|
| var data = {};
|
| mirrorMap.forEach((String mirrorName, MethodMirror mirror) {
|
| - _currentMember = mirror;
|
| - data[mirrorName] = new Method(mirrorName, mirror.isSetter,
|
| - mirror.isGetter, mirror.isConstructor, mirror.isOperator,
|
| - mirror.isStatic, mirror.returnType.toString(), _getComment(mirror),
|
| - _getParameters(mirror.parameters));
|
| + if (includePrivate || !mirror.isPrivate) {
|
| + _currentMember = mirror;
|
| + data[mirrorName] = new Method(mirrorName, mirror.isSetter,
|
| + mirror.isGetter, mirror.isConstructor, mirror.isOperator,
|
| + mirror.isStatic, mirror.returnType.toString(), _getComment(mirror),
|
| + _getParameters(mirror.parameters), nextID);
|
| + }
|
| });
|
| return data;
|
| }
|
| @@ -169,16 +279,17 @@ class Docgen {
|
| Map<String, Class> _getClasses(Map<String, ClassMirror> mirrorMap) {
|
| var data = {};
|
| mirrorMap.forEach((String mirrorName, ClassMirror mirror) {
|
| - _currentClass = mirror;
|
| - var superclass;
|
| - if (mirror.superclass != null) {
|
| - superclass = mirror.superclass.qualifiedName;
|
| + if (includePrivate || !mirror.isPrivate) {
|
| + _currentClass = mirror;
|
| + var superclass = (mirror.superclass != null) ?
|
| + mirror.superclass.qualifiedName : "";
|
| + var interfaces =
|
| + mirror.superinterfaces.map((interface) => interface.qualifiedName);
|
| + data[mirrorName] = new Class(mirrorName, superclass, mirror.isAbstract,
|
| + mirror.isTypedef, _getComment(mirror), interfaces.toList(),
|
| + _getVariables(mirror.variables), _getMethods(mirror.methods),
|
| + nextID);
|
| }
|
| - var interfaces =
|
| - mirror.superinterfaces.map((interface) => interface.qualifiedName);
|
| - data[mirrorName] = new Class(mirrorName, superclass, mirror.isAbstract,
|
| - mirror.isTypedef, _getComment(mirror), interfaces,
|
| - _getVariables(mirror.variables), _getMethods(mirror.methods));
|
| });
|
| return data;
|
| }
|
| @@ -192,7 +303,7 @@ class Docgen {
|
| _currentMember = mirror;
|
| data[mirror.simpleName] = new Parameter(mirror.simpleName,
|
| mirror.isOptional, mirror.isNamed, mirror.hasDefaultValue,
|
| - mirror.type.toString(), mirror.defaultValue);
|
| + mirror.type.toString(), mirror.defaultValue, nextID);
|
| });
|
| return data;
|
| }
|
| @@ -214,6 +325,9 @@ Map recurseMap(Map inputMap) {
|
| */
|
| class Library {
|
|
|
| + /// Unique ID number for resolving links.
|
| + int id;
|
| +
|
| /// Documentation comment with converted markdown.
|
| String comment;
|
|
|
| @@ -229,11 +343,12 @@ class Library {
|
| String name;
|
|
|
| Library(this.name, this.comment, this.variables,
|
| - this.functions, this.classes);
|
| + this.functions, this.classes, this.id);
|
|
|
| /// Generates a map describing the [Library] object.
|
| Map toMap() {
|
| var libraryMap = {};
|
| + libraryMap["id"] = id;
|
| libraryMap["name"] = name;
|
| libraryMap["comment"] = comment;
|
| libraryMap["variables"] = recurseMap(variables);
|
| @@ -249,6 +364,9 @@ class Library {
|
| // TODO(tmandel): Figure out how to do typedefs (what is needed)
|
| class Class {
|
|
|
| + /// Unique ID number for resolving links.
|
| + int id;
|
| +
|
| /// Documentation comment with converted markdown.
|
| String comment;
|
|
|
| @@ -267,11 +385,12 @@ class Class {
|
| bool isTypedef;
|
|
|
| Class(this.name, this.superclass, this.isAbstract, this.isTypedef,
|
| - this.comment, this.interfaces, this.variables, this.methods);
|
| + this.comment, this.interfaces, this.variables, this.methods, this.id);
|
|
|
| /// Generates a map describing the [Class] object.
|
| Map toMap() {
|
| var classMap = {};
|
| + classMap["id"] = id;
|
| classMap["name"] = name;
|
| classMap["comment"] = comment;
|
| classMap["superclass"] = superclass;
|
| @@ -289,6 +408,9 @@ class Class {
|
| */
|
| class Variable {
|
|
|
| + /// Unique ID number for resolving links.
|
| + int id;
|
| +
|
| /// Documentation comment with converted markdown.
|
| String comment;
|
|
|
| @@ -297,11 +419,13 @@ class Variable {
|
| bool isStatic;
|
| String type;
|
|
|
| - Variable(this.name, this.isFinal, this.isStatic, this.type, this.comment);
|
| + Variable(this.name, this.isFinal, this.isStatic, this.type,
|
| + this.comment, this.id);
|
|
|
| /// Generates a map describing the [Variable] object.
|
| Map toMap() {
|
| var variableMap = {};
|
| + variableMap["id"] = id;
|
| variableMap["name"] = name;
|
| variableMap["comment"] = comment;
|
| variableMap["final"] = isFinal.toString();
|
| @@ -316,6 +440,9 @@ class Variable {
|
| */
|
| class Method {
|
|
|
| + /// Unique ID number for resolving links.
|
| + int id;
|
| +
|
| /// Documentation comment with converted markdown.
|
| String comment;
|
|
|
| @@ -332,11 +459,12 @@ class Method {
|
|
|
| Method(this.name, this.isSetter, this.isGetter, this.isConstructor,
|
| this.isOperator, this.isStatic, this.returnType, this.comment,
|
| - this.parameters);
|
| + this.parameters, this.id);
|
|
|
| /// Generates a map describing the [Method] object.
|
| Map toMap() {
|
| var methodMap = {};
|
| + methodMap["id"] = id;
|
| methodMap["name"] = name;
|
| methodMap["comment"] = comment;
|
| methodMap["type"] = isSetter ? "setter" : isGetter ? "getter" :
|
| @@ -353,6 +481,9 @@ class Method {
|
| */
|
| class Parameter {
|
|
|
| + /// Unique ID number for resolving links.
|
| + int id;
|
| +
|
| String name;
|
| bool isOptional;
|
| bool isNamed;
|
| @@ -361,11 +492,12 @@ class Parameter {
|
| String defaultValue;
|
|
|
| Parameter(this.name, this.isOptional, this.isNamed, this.hasDefaultValue,
|
| - this.type, this.defaultValue);
|
| + this.type, this.defaultValue, this.id);
|
|
|
| /// Generates a map describing the [Parameter] object.
|
| Map toMap() {
|
| var parameterMap = {};
|
| + parameterMap["id"] = id;
|
| parameterMap["name"] = name;
|
| parameterMap["optional"] = isOptional.toString();
|
| parameterMap["named"] = isNamed.toString();
|
| @@ -385,7 +517,7 @@ void _writeToFile(String text, String filename) {
|
| dir.createSync();
|
| }
|
| File file = new File('docs/$filename');
|
| - if (!file.exists()) {
|
| + if (!file.existsSync()) {
|
| file.createSync();
|
| }
|
| file.openSync();
|
|
|