| Index: pkg/docgen/lib/docgen.dart
|
| diff --git a/pkg/docgen/lib/docgen.dart b/pkg/docgen/lib/docgen.dart
|
| index 168b6370d318259d93217041c31d65303b711397..d4704ce4fca192142e40200912afdeb172e11957 100644
|
| --- a/pkg/docgen/lib/docgen.dart
|
| +++ b/pkg/docgen/lib/docgen.dart
|
| @@ -96,12 +96,6 @@ and
|
| [Writing API Documentation](https://code.google.com/p/dart/wiki/WritingApiDocumentation).
|
| """;
|
|
|
| -// TODO(efortuna): The use of this field is odd (this is based on how it was
|
| -// originally used. Try to cleanup.
|
| -/// Index of all indexable items. This also ensures that no class is
|
| -/// created more than once.
|
| -Map<String, Indexable> entityMap = new Map<String, Indexable>();
|
| -
|
| /// Docgen constructor initializes the link resolver for markdown parsing.
|
| /// Also initializes the command line arguments.
|
| ///
|
| @@ -110,19 +104,37 @@ Map<String, Indexable> entityMap = new Map<String, Indexable>();
|
| /// also be documented.
|
| /// If [parseSdk] is `true`, then all Dart SDK libraries will be documented.
|
| /// This option is useful when only the SDK libraries are needed.
|
| +/// If [serve] is `true`, then after generating the documents we fire up a
|
| +/// simple server to view the documentation.
|
| ///
|
| /// Returned Future completes with true if document generation is successful.
|
| Future<bool> docgen(List<String> files, {String packageRoot,
|
| bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false,
|
| bool parseSdk: false, bool append: false, String introFileName: '',
|
| out: _DEFAULT_OUTPUT_DIRECTORY, List<String> excludeLibraries : const [],
|
| - bool includeDependentPackages: false}) {
|
| - return _Generator.generateDocumentation(files, packageRoot: packageRoot,
|
| - outputToYaml: outputToYaml, includePrivate: includePrivate,
|
| - includeSdk: includeSdk, parseSdk: parseSdk, append: append,
|
| - introFileName: introFileName, out: out,
|
| - excludeLibraries: excludeLibraries,
|
| - includeDependentPackages: includeDependentPackages);
|
| + bool includeDependentPackages: false, bool serve: false,
|
| + bool noDocs: false}) {
|
| + var result;
|
| + if (!noDocs) {
|
| + _Viewer.ensureMovedViewerCode();
|
| + result = _Generator.generateDocumentation(files, packageRoot: packageRoot,
|
| + outputToYaml: outputToYaml, includePrivate: includePrivate,
|
| + includeSdk: includeSdk, parseSdk: parseSdk, append: append,
|
| + introFileName: introFileName, out: out,
|
| + excludeLibraries: excludeLibraries,
|
| + includeDependentPackages: includeDependentPackages);
|
| + _Viewer.addBackViewerCode();
|
| + if (serve) {
|
| + result.then((success) {
|
| + if (success) {
|
| + _Viewer._cloneAndServe();
|
| + }
|
| + });
|
| + }
|
| + } else if (serve) {
|
| + _Viewer._cloneAndServe();
|
| + }
|
| + return result;
|
| }
|
|
|
| /// Analyzes set of libraries by getting a mirror system and triggers the
|
| @@ -189,6 +201,7 @@ class DummyMirror implements Indexable {
|
| /// Docgen representation of an item to be documented, that wraps around a
|
| /// dart2js mirror.
|
| abstract class MirrorBased {
|
| + /// The original dart2js mirror around which this object wraps.
|
| DeclarationMirror get mirror;
|
|
|
| /// Returns a list of meta annotations assocated with a mirror.
|
| @@ -208,8 +221,14 @@ abstract class MirrorBased {
|
| }
|
| }
|
|
|
| +/// Top level documentation traversal and generation object.
|
| +///
|
| +/// Yes, everything in this class is used statically so this technically doesn't
|
| +/// need to be its own class, but it's grouped together for semantic separation
|
| +/// from the other classes and functionality in this library.
|
| class _Generator {
|
| - static var _outputDirectory;
|
| + /// The directory where the output docs are generated.
|
| + static String _outputDirectory;
|
|
|
| /// This is set from the command line arguments flag --include-private
|
| static bool _includePrivate = false;
|
| @@ -220,6 +239,7 @@ class _Generator {
|
| /// --exclude-lib.
|
| static List<String> _excluded;
|
|
|
| + /// Logger for printing out progress of documentation generation.
|
| static Logger logger = new Logger('Docgen');
|
|
|
| /// Docgen constructor initializes the link resolver for markdown parsing.
|
| @@ -259,7 +279,7 @@ class _Generator {
|
| if (mirrorSystem.libraries.isEmpty) {
|
| throw new StateError('No library mirrors were created.');
|
| }
|
| - Indexable.initializeTopLevelLibraries(mirrorSystem);
|
| + Indexable._initializeTopLevelLibraries(mirrorSystem);
|
|
|
| var availableLibraries = mirrorSystem.libraries.values.where(
|
| (each) => each.uri.scheme == 'file');
|
| @@ -305,6 +325,21 @@ class _Generator {
|
| mode: append ? FileMode.APPEND : FileMode.WRITE);
|
| }
|
|
|
| + /// Resolve all the links in the introductory comments for a given library or
|
| + /// package as specified by [filename].
|
| + static String _readIntroductionFile(String fileName, bool includeSdk) {
|
| + var linkResolver = (name) => Indexable.globalFixReference(name);
|
| + var defaultText = includeSdk ? _DEFAULT_SDK_INTRODUCTION : '';
|
| + var introText = defaultText;
|
| + if (fileName.isNotEmpty) {
|
| + var introFile = new File(fileName);
|
| + introText = introFile.existsSync() ? introFile.readAsStringSync() :
|
| + defaultText;
|
| + }
|
| + return markdown.markdownToHtml(introText,
|
| + linkResolver: linkResolver, inlineSyntaxes: _MARKDOWN_SYNTAXES);
|
| + }
|
| +
|
| /// Creates documentation for filtered libraries.
|
| static void _documentLibraries(List<LibraryMirror> libs,
|
| {bool includeSdk: false, bool outputToYaml: true, bool append: false,
|
| @@ -313,48 +348,27 @@ class _Generator {
|
| // Files belonging to the SDK have a uri that begins with 'dart:'.
|
| if (includeSdk || !lib.uri.toString().startsWith('dart:')) {
|
| var library = generateLibrary(lib);
|
| - entityMap[library.name] = library;
|
| }
|
| });
|
|
|
| - var filteredEntities = entityMap.values.where(_isFullChainVisible);
|
| -
|
| - /*var filteredEntities2 = new Set<MirrorBased>();
|
| - for (Map<String, Set<MirrorBased>> firstLevel in mirrorToDocgen.values) {
|
| - for (Set<MirrorBased> items in firstLevel.values) {
|
| - for (MirrorBased item in items) {
|
| + var filteredEntities = new Set<Indexable>();
|
| + for (Map<String, Set<Indexable>> firstLevel in
|
| + Indexable._mirrorToDocgen.values) {
|
| + for (Set<Indexable> items in firstLevel.values) {
|
| + for (Indexable item in items) {
|
| if (_isFullChainVisible(item)) {
|
| - filteredEntities2.add(item);
|
| + if (item is! Method ||
|
| + (item is Method && item.methodInheritedFrom == null)) {
|
| + filteredEntities.add(item);
|
| + }
|
| }
|
| }
|
| }
|
| - }*/
|
| -
|
| - /*print('THHHHHEEE DIFFERENCE IS');
|
| - var set1 = new Set.from(filteredEntities);
|
| - var set2 = new Set.from(filteredEntities2);
|
| - var aResult = set2.difference(set1);
|
| - for (MirrorBased r in aResult) {
|
| - print(' a result is $r and ${r.docName}');
|
| - }*/
|
| - //print(set1.difference(set2));
|
| + }
|
|
|
| // Outputs a JSON file with all libraries and their preview comments.
|
| // This will help the viewer know what libraries are available to read in.
|
| var libraryMap;
|
| - var linkResolver = (name) => Indexable.globalFixReference(name);
|
| -
|
| - String readIntroductionFile(String fileName, includeSdk) {
|
| - var defaultText = includeSdk ? _DEFAULT_SDK_INTRODUCTION : '';
|
| - var introText = defaultText;
|
| - if (fileName.isNotEmpty) {
|
| - var introFile = new File(fileName);
|
| - introText = introFile.existsSync() ? introFile.readAsStringSync() :
|
| - defaultText;
|
| - }
|
| - return markdown.markdownToHtml(introText,
|
| - linkResolver: linkResolver, inlineSyntaxes: _MARKDOWN_SYNTAXES);
|
| - }
|
|
|
| if (append) {
|
| var docsDir = listDir(_outputDirectory);
|
| @@ -370,16 +384,23 @@ class _Generator {
|
| var intro = libraryMap['introduction'];
|
| var spacing = intro.isEmpty ? '' : '<br/><br/>';
|
| libraryMap['introduction'] =
|
| - "$intro$spacing${readIntroductionFile(introFileName, includeSdk)}";
|
| + "$intro$spacing${_readIntroductionFile(introFileName, includeSdk)}";
|
| outputToYaml = libraryMap['filetype'] == 'yaml';
|
| } else {
|
| libraryMap = {
|
| 'libraries' : filteredEntities.where((e) =>
|
| e is Library).map((e) => e.previewMap).toList(),
|
| - 'introduction' : readIntroductionFile(introFileName, includeSdk),
|
| + 'introduction' : _readIntroductionFile(introFileName, includeSdk),
|
| 'filetype' : outputToYaml ? 'yaml' : 'json'
|
| };
|
| }
|
| + _writeOutputFiles(libraryMap, filteredEntities, outputToYaml, append);
|
| + }
|
| +
|
| + /// Output all of the libraries and classes into json or yaml files for
|
| + /// consumption by a viewer.
|
| + static void _writeOutputFiles(libraryMap,
|
| + Iterable<Indexable> filteredEntities, bool outputToYaml, bool append) {
|
| _writeToFile(JSON.encode(libraryMap), 'library_list.json');
|
|
|
| // Output libraries and classes to file after all information is generated.
|
| @@ -404,6 +425,7 @@ class _Generator {
|
| _writeToFile(JSON.encode(index), 'index.json');
|
| }
|
|
|
| + /// Helper method to serialize the given Indexable out to a file.
|
| static void _writeIndexableToFile(Indexable result, bool outputToYaml) {
|
| var outputFile = result.fileName;
|
| var output;
|
| @@ -427,7 +449,8 @@ class _Generator {
|
| }
|
| }
|
|
|
| -
|
| + /// Helper accessor to determine the full pathname of the root of the dart
|
| + /// checkout.
|
| static String get _rootDirectory {
|
| var scriptDir = path.absolute(path.dirname(Platform.script.toFilePath()));
|
| var root = scriptDir;
|
| @@ -472,11 +495,6 @@ class _Generator {
|
| static String _obtainPackageRoot(String packageRoot, bool parseSdk,
|
| List<String> files) {
|
| if (packageRoot == null && !parseSdk) {
|
| - // TODO(efortuna): This logic seems not very robust, but it's from the
|
| - // original version of the code, pre-refactor, so I'm leavingt it for now.
|
| - // Revisit to make more robust.
|
| - // TODO(efortuna): See lines 303-311 in
|
| - // https://codereview.chromium.org/116043013/diff/390001/pkg/docgen/lib/docgen.dart
|
| var type = FileSystemEntity.typeSync(files.first);
|
| if (type == FileSystemEntityType.DIRECTORY) {
|
| var files2 = listDir(files.first, recursive: true);
|
| @@ -570,12 +588,10 @@ class _Generator {
|
| return sdk;
|
| }
|
|
|
| + /// Return true if this item and all of its owners are all visible.
|
| static bool _isFullChainVisible(Indexable item) {
|
| - // TODO: reconcile with isVisible.
|
| - // TODO: Also should be able to take MirrorBased items in general probably.
|
| - var result = _includePrivate || (!item.isPrivate && (item.owner != null ?
|
| + return _includePrivate || (!item.isPrivate && (item.owner != null ?
|
| _isFullChainVisible(item.owner) : true));
|
| - return result;
|
| }
|
|
|
| /// Currently left public for testing purposes. :-/
|
| @@ -587,6 +603,129 @@ class _Generator {
|
| }
|
| }
|
|
|
| +/// Convenience methods wrapped up in a class to pull down the docgen viewer for
|
| +/// a viewable website, and start up a server for viewing.
|
| +class _Viewer {
|
| + static String _dartdocViewerString = path.join(Directory.current.path,
|
| + 'dartdoc-viewer');
|
| + static Directory _dartdocViewerDir = new Directory(_dartdocViewerString);
|
| + static Directory _topLevelTempDir;
|
| + static bool movedViewerCode = false;
|
| +
|
| + /// If our dartdoc-viewer code is already checked out, move it to a temporary
|
| + /// directory outside of the package directory, so we don't try to process it
|
| + /// for documentation.
|
| + static void ensureMovedViewerCode() {
|
| + // TODO(efortuna): This will need to be modified to run on anyone's package
|
| + // outside of the checkout!
|
| + if (_dartdocViewerDir.existsSync()) {
|
| + _topLevelTempDir = new Directory(
|
| + _Generator._rootDirectory).createTempSync();
|
| + _dartdocViewerDir.renameSync(_topLevelTempDir.path);
|
| + }
|
| + }
|
| +
|
| + /// Move the dartdoc-viewer code back into place for "webpage deployment."
|
| + static void addBackViewerCode() {
|
| + if (movedViewerCode) _dartdocViewerDir.renameSync(_dartdocViewerString);
|
| + }
|
| +
|
| + /// Serve up our generated documentation for viewing in a browser.
|
| + static void _cloneAndServe() {
|
| + // If the viewer code is already there, then don't clone again.
|
| + if (_dartdocViewerDir.existsSync()) {
|
| + _moveDirectoryAndServe();
|
| + }
|
| + else {
|
| + var processResult = Process.runSync('git', ['clone', '-b', 'master',
|
| + 'git://github.com/dart-lang/dartdoc-viewer.git'],
|
| + runInShell: true);
|
| +
|
| + if (processResult.exitCode == 0) {
|
| + _moveDirectoryAndServe();
|
| + } else {
|
| + print('Error cloning git repository:');
|
| + print('process output: ${processResult.stdout}');
|
| + print('process stderr: ${processResult.stderr}');
|
| + }
|
| + }
|
| + }
|
| +
|
| + /// Move the generated json/yaml docs directory to the dartdoc-viewer
|
| + /// directory, to run as a webpage.
|
| + static void _moveDirectoryAndServe() {
|
| + var dir = new Directory(_Generator._outputDirectory == null? 'docs' :
|
| + _Generator._outputDirectory);
|
| + var webDocsDir = new Directory(path.join(_dartdocViewerDir.path, 'client',
|
| + 'web', 'docs'));
|
| + if (dir.existsSync()) {
|
| + // Move the docs folder to dartdoc-viewer/client/web/docs
|
| + dir.renameSync(webDocsDir.path);
|
| + }
|
| +
|
| + if (webDocsDir.existsSync()) {
|
| + // Compile the code to JavaScript so we can run on any browser.
|
| + print('Compile app to JavaScript for viewing.');
|
| + var processResult = Process.runSync('dart', ['deploy.dart'],
|
| + workingDirectory : path.join(_dartdocViewerDir.path, 'client'),
|
| + runInShell: true);
|
| + print('process output: ${processResult.stdout}');
|
| + print('process stderr: ${processResult.stderr}');
|
| + _runServer();
|
| + }
|
| + }
|
| +
|
| + /// A simple HTTP server. Implemented here because this is part of the SDK,
|
| + /// so it shouldn't have any external dependencies.
|
| + static void _runServer() {
|
| + // Launch a server to serve out of the directory dartdoc-viewer/client/web.
|
| + HttpServer.bind('localhost', 8080).then((HttpServer httpServer) {
|
| + print('Server launched. Navigate your browser to: '
|
| + 'http://localhost:${httpServer.port}');
|
| + httpServer.listen((HttpRequest request) {
|
| + var response = request.response;
|
| + var basePath = path.join(_dartdocViewerDir.path, 'client', 'out',
|
| + 'web');
|
| + var requestPath = path.join(basePath, request.uri.path.substring(1));
|
| + bool found = true;
|
| + var file = new File(requestPath);
|
| + if (file.existsSync()) {
|
| + // Set the correct header type.
|
| + if (requestPath.endsWith('.html')) {
|
| + response.headers.set('Content-Type', 'text/html');
|
| + } else if (requestPath.endsWith('.js')) {
|
| + response.headers.set('Content-Type', 'application/javascript');
|
| + } else if (requestPath.endsWith('.dart')) {
|
| + response.headers.set('Content-Type', 'application/dart');
|
| + } else if (requestPath.endsWith('.css')) {
|
| + response.headers.set('Content-Type', 'text/css');
|
| + }
|
| + } else {
|
| + if (requestPath == basePath) {
|
| + response.headers.set('Content-Type', 'text/html');
|
| + file = new File(path.join(basePath, 'index.html'));
|
| + } else {
|
| + print('Path not found: $requestPath');
|
| + found = false;
|
| + response.statusCode = HttpStatus.NOT_FOUND;
|
| + response.close();
|
| + }
|
| + }
|
| +
|
| + if (found) {
|
| + // Serve up file contents.
|
| + file.openRead().pipe(response).catchError((e) {
|
| + print('HttpServer: error while closing the response stream $e');
|
| + });
|
| + }
|
| + },
|
| + onError: (e) {
|
| + print('HttpServer: an error occured $e');
|
| + });
|
| + });
|
| + }
|
| +}
|
| +
|
| /// An item that is categorized in our mirrorToDocgen map, as a distinct,
|
| /// searchable element.
|
| ///
|
| @@ -647,7 +786,7 @@ abstract class Indexable extends MirrorBased {
|
| return _getOwningLibrary(indexable.owner);
|
| }
|
|
|
| - static initializeTopLevelLibraries(MirrorSystem mirrorSystem) {
|
| + static _initializeTopLevelLibraries(MirrorSystem mirrorSystem) {
|
| _sdkLibraries = mirrorSystem.libraries.values.where(
|
| (each) => each.uri.scheme == 'dart');
|
| _coreLibrary = new Library(_sdkLibraries.singleWhere((lib) =>
|
| @@ -659,8 +798,6 @@ abstract class Indexable extends MirrorBased {
|
| /// have them replaced with hyphens.
|
| String get docName;
|
|
|
| - markdown.Node fixReferenceWithScope(String name) => null;
|
| -
|
| /// Converts all [foo] references in comments to <a>libraryName.foo</a>.
|
| markdown.Node fixReference(String name) {
|
| // Attempt the look up the whole name up in the scope.
|
| @@ -676,24 +813,36 @@ abstract class Indexable extends MirrorBased {
|
| String findElementInScope(String name) =>
|
| _findElementInScope(name, packagePrefix);
|
|
|
| + /// For a given name, determine if we need to resolve it as a qualified name
|
| + /// or a simple name in the source mirors.
|
| static determineLookupFunc(name) => name.contains('.') ?
|
| dart2js_util.lookupQualifiedInScope :
|
| (mirror, name) => mirror.lookupInScope(name);
|
|
|
| - // The qualified name (for URL purposes) and the file name are the same,
|
| - // of the form packageName/ClassName or packageName/ClassName.methodName.
|
| - // This defines both the URL and the directory structure.
|
| - String get fileName {
|
| - return packagePrefix + ownerPrefix + name;
|
| - }
|
| + /// The reference to this element based on where it is printed as a
|
| + /// documentation file and also the unique URL to refer to this item.
|
| + ///
|
| + /// The qualified name (for URL purposes) and the file name are the same,
|
| + /// of the form packageName/ClassName or packageName/ClassName.methodName.
|
| + /// This defines both the URL and the directory structure.
|
| + String get fileName => packagePrefix + ownerPrefix + name;
|
|
|
| + /// The full docName of the owner element, appended with a '.' for this
|
| + /// object's name to be appended.
|
| String get ownerPrefix => owner.docName != '' ? owner.docName + '.' : '';
|
|
|
| + /// The prefix String to refer to the package that this item is in, for URLs
|
| + /// and comment resolution.
|
| + ///
|
| + /// The prefix can be prepended to a qualified name to get a fully unique
|
| + /// name among all packages.
|
| String get packagePrefix => '';
|
|
|
| - /// Documentation comment with converted markdown.
|
| + /// Documentation comment with converted markdown and all links resolved.
|
| String _comment;
|
|
|
| + /// Accessor to documentation comment with markdown converted to html and all
|
| + /// links resolved.
|
| String get comment {
|
| if (_comment != null) return _comment;
|
|
|
| @@ -706,30 +855,19 @@ abstract class Indexable extends MirrorBased {
|
|
|
| set comment(x) => _comment = x;
|
|
|
| + /// The simple name to refer to this item.
|
| String get name => mirror.simpleName;
|
|
|
| + /// Accessor to the parent item that owns this item.
|
| + ///
|
| + /// "Owning" is defined as the object one scope-level above which this item
|
| + /// is defined. Ex: The owner for a top level class, would be its enclosing
|
| + /// library. The owner of a local variable in a method would be the enclosing
|
| + /// method.
|
| Indexable get owner => new DummyMirror(mirror.owner);
|
|
|
| /// Generates MDN comments from database.json.
|
| - String _mdnComment() {
|
| - //Check if MDN is loaded.
|
| - if (_mdn == null) {
|
| - // Reading in MDN related json file.
|
| - var root = _Generator._rootDirectory;
|
| - var mdnPath = path.join(root, 'utils/apidoc/mdn/database.json');
|
| - _mdn = JSON.decode(new File(mdnPath).readAsStringSync());
|
| - }
|
| - // TODO: refactor OOP
|
| - if (this is Library) return '';
|
| - var domAnnotation = this.annotations.firstWhere(
|
| - (e) => e.mirror.qualifiedName == 'metadata.DomName',
|
| - orElse: () => null);
|
| - if (domAnnotation == null) return '';
|
| - var domName = domAnnotation.parameters.single;
|
| - var parts = domName.split('.');
|
| - if (parts.length == 2) return _mdnMemberComment(parts[0], parts[1]);
|
| - if (parts.length == 1) return _mdnTypeComment(parts[0]);
|
| - }
|
| + String _mdnComment();
|
|
|
| /// Generates the MDN Comment for variables and method DOM elements.
|
| String _mdnMemberComment(String type, String member) {
|
| @@ -740,7 +878,7 @@ abstract class Indexable extends MirrorBased {
|
| if (mdnMember == null) return '';
|
| if (mdnMember['help'] == null || mdnMember['help'] == '') return '';
|
| if (mdnMember['url'] == null) return '';
|
| - return _htmlMdn(mdnMember['help'], mdnMember['url']);
|
| + return _htmlifyMdn(mdnMember['help'], mdnMember['url']);
|
| }
|
|
|
| /// Generates the MDN Comment for class DOM elements.
|
| @@ -749,10 +887,11 @@ abstract class Indexable extends MirrorBased {
|
| if (mdnType == null) return '';
|
| if (mdnType['summary'] == null || mdnType['summary'] == "") return '';
|
| if (mdnType['srcUrl'] == null) return '';
|
| - return _htmlMdn(mdnType['summary'], mdnType['srcUrl']);
|
| + return _htmlifyMdn(mdnType['summary'], mdnType['srcUrl']);
|
| }
|
|
|
| - String _htmlMdn(String content, String url) {
|
| + /// Encloses the given content in an MDN div and the original source link.
|
| + String _htmlifyMdn(String content, String url) {
|
| return '<div class="mdn">' + content.trim() + '<p class="mdn-note">'
|
| '<a href="' + url.trim() + '">from Mdn</a></p></div>';
|
| }
|
| @@ -770,7 +909,9 @@ abstract class Indexable extends MirrorBased {
|
| return finalMap;
|
| }
|
|
|
| - String _getCommentText() {
|
| + /// Accessor to obtain the raw comment text for a given item, _without_ any
|
| + /// of the links resolved.
|
| + String get _commentText {
|
| String commentText;
|
| mirror.metadata.forEach((metadata) {
|
| if (metadata is CommentInstanceMirror) {
|
| @@ -795,10 +936,10 @@ abstract class Indexable extends MirrorBased {
|
| /// links to the subclasses's version of the methods.
|
| String _commentToHtml([Indexable resolvingScope]) {
|
| if (resolvingScope == null) resolvingScope = this;
|
| - var commentText = _getCommentText();
|
| + var commentText = _commentText;
|
| _unresolvedComment = commentText;
|
|
|
| - var linkResolver = (name) => resolvingScope.fixReferenceWithScope(name);
|
| + var linkResolver = (name) => resolvingScope.fixReference(name);
|
| commentText = commentText == null ? '' :
|
| markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver,
|
| inlineSyntaxes: _MARKDOWN_SYNTAXES);
|
| @@ -816,9 +957,7 @@ abstract class Indexable extends MirrorBased {
|
| // with a filter. Issue(#9590).
|
| mirrorMap.forEach((String mirrorName, VariableMirror mirror) {
|
| if (_Generator._includePrivate || !_isHidden(mirror)) {
|
| - var variable = new Variable(mirrorName, mirror, owner);
|
| - entityMap[variable.docName] = variable;
|
| - data[mirrorName] = entityMap[variable.docName];
|
| + data[mirrorName] = new Variable(mirrorName, mirror, owner);
|
| }
|
| });
|
| return data;
|
| @@ -833,9 +972,7 @@ abstract class Indexable extends MirrorBased {
|
| var group = new Map<String, Method>();
|
| mirrorMap.forEach((String mirrorName, MethodMirror mirror) {
|
| if (_Generator._includePrivate || !mirror.isPrivate) {
|
| - var method = new Method(mirror, owner);
|
| - entityMap[method.docName] = method;
|
| - group[mirror.simpleName] = method;
|
| + group[mirror.simpleName] = new Method(mirror, owner);
|
| }
|
| });
|
| return group;
|
| @@ -862,8 +999,7 @@ abstract class Indexable extends MirrorBased {
|
| String toString() => "${super.toString()}(${name.toString()})";
|
|
|
| /// Return a map representation of this type.
|
| - Map toMap() {}
|
| -
|
| + Map toMap();
|
|
|
| /// A declaration is private if itself is private, or the owner is private.
|
| // Issue(12202) - A declaration is public even if it's owner is private.
|
| @@ -884,8 +1020,9 @@ abstract class Indexable extends MirrorBased {
|
| ///
|
| /// An example that starts with _ is _js_helper.
|
| /// An example that contains ._ is dart._collection.dev
|
| - // This is because LibraryMirror.isPrivate returns `false` all the time.
|
| bool _isLibraryPrivate(LibraryMirror mirror) {
|
| + // This method is needed because LibraryMirror.isPrivate returns `false` all
|
| + // the time.
|
| var sdkLibrary = LIBRARIES[mirror.simpleName];
|
| if (sdkLibrary != null) {
|
| return !sdkLibrary.documented;
|
| @@ -1011,16 +1148,18 @@ abstract class Indexable extends MirrorBased {
|
| return null;
|
| }
|
|
|
| - Map expandMethodMap(Map<String, Method> mapToExpand) => {
|
| - 'setters': recurseMap(_filterMap(new Map(), mapToExpand,
|
| + /// Expand the method map [mapToExpand] into a more detailed map that
|
| + /// separates out setters, getters, constructors, operators, and methods.
|
| + Map _expandMethodMap(Map<String, Method> mapToExpand) => {
|
| + 'setters': recurseMap(_filterMap(mapToExpand,
|
| (key, val) => val.mirror.isSetter)),
|
| - 'getters': recurseMap(_filterMap(new Map(), mapToExpand,
|
| + 'getters': recurseMap(_filterMap(mapToExpand,
|
| (key, val) => val.mirror.isGetter)),
|
| - 'constructors': recurseMap(_filterMap(new Map(), mapToExpand,
|
| + 'constructors': recurseMap(_filterMap(mapToExpand,
|
| (key, val) => val.mirror.isConstructor)),
|
| - 'operators': recurseMap(_filterMap(new Map(), mapToExpand,
|
| + 'operators': recurseMap(_filterMap(mapToExpand,
|
| (key, val) => val.mirror.isOperator)),
|
| - 'methods': recurseMap(_filterMap(new Map(), mapToExpand,
|
| + 'methods': recurseMap(_filterMap(mapToExpand,
|
| (key, val) => val.mirror.isRegularMethod && !val.mirror.isOperator))
|
| };
|
|
|
| @@ -1037,14 +1176,16 @@ abstract class Indexable extends MirrorBased {
|
| return outputMap;
|
| }
|
|
|
| - Map _filterMap(exported, map, test) {
|
| + Map _filterMap(Map map, Function test) {
|
| + var exported = new Map();
|
| map.forEach((key, value) {
|
| if (test(key, value)) exported[key] = value;
|
| });
|
| return exported;
|
| }
|
|
|
| - bool get _isVisible => _Generator._includePrivate || !isPrivate;
|
| + /// Accessor to determine if this item and all of its owners are visible.
|
| + bool get _isVisible => _Generator._isFullChainVisible(this);
|
|
|
| /// Given a Dart2jsMirror, find the corresponding Docgen [MirrorBased] object.
|
| ///
|
| @@ -1090,6 +1231,8 @@ abstract class Indexable extends MirrorBased {
|
| return new DummyMirror(mirror, owner);
|
| }
|
|
|
| + /// Returns true if [mirror] is the correct type of mirror that this Docgen
|
| + /// object wraps. (Workaround for the fact that Types are not first class.)
|
| bool _isValidMirror(DeclarationMirror mirror);
|
| }
|
|
|
| @@ -1107,7 +1250,7 @@ class Library extends Indexable {
|
| Map<String, Class> errors = {};
|
|
|
| String packageName = '';
|
| - bool hasBeenCheckedForPackage = false;
|
| + bool _hasBeenCheckedForPackage = false;
|
| String packageIntro;
|
|
|
| /// Returns the [Library] for the given [mirror] if it has already been
|
| @@ -1133,9 +1276,7 @@ class Library extends Indexable {
|
| // but we don't have visibility to that type.
|
| var mirror = classMirror;
|
| if (_Generator._includePrivate || !mirror.isPrivate) {
|
| - var aTypedef = new Typedef(mirror, this);
|
| - entityMap[Indexable.getDocgenObject(mirror).docName] = aTypedef;
|
| - typedefs[mirror.simpleName] = aTypedef;
|
| + typedefs[mirror.simpleName] = new Typedef(mirror, this);
|
| }
|
| } else {
|
| var clazz = new Class(classMirror, this);
|
| @@ -1169,14 +1310,16 @@ class Library extends Indexable {
|
| return super.findElementInScope(name);
|
| }
|
|
|
| + String _mdnComment() => '';
|
| +
|
| /// For a library's [mirror], determine the name of the package (if any) we
|
| /// believe it came from (because of its file URI).
|
| ///
|
| /// If no package could be determined, we return an empty string.
|
| String _findPackage(LibraryMirror mirror) {
|
| if (mirror == null) return '';
|
| - if (hasBeenCheckedForPackage) return packageName;
|
| - hasBeenCheckedForPackage = true;
|
| + if (_hasBeenCheckedForPackage) return packageName;
|
| + _hasBeenCheckedForPackage = true;
|
| if (mirror.uri.scheme != 'file') return '';
|
| // We assume that we are documenting only libraries under package/lib
|
| packageName = _packageName(mirror);
|
| @@ -1221,8 +1364,6 @@ class Library extends Indexable {
|
| return spec["name"];
|
| }
|
|
|
| - markdown.Node fixReferenceWithScope(String name) => fixReference(name);
|
| -
|
| String get packagePrefix => packageName == null || packageName.isEmpty ?
|
| '' : '$packageName/';
|
|
|
| @@ -1302,9 +1443,8 @@ class Library extends Indexable {
|
| }
|
|
|
| /// Checks if the given name is a key for any of the Class Maps.
|
| - bool containsKey(String name) {
|
| - return classes.containsKey(name) || errors.containsKey(name);
|
| - }
|
| + bool containsKey(String name) =>
|
| + classes.containsKey(name) || errors.containsKey(name);
|
|
|
| /// Generates a map describing the [Library] object.
|
| Map toMap() => {
|
| @@ -1312,7 +1452,7 @@ class Library extends Indexable {
|
| 'qualifiedName': qualifiedName,
|
| 'comment': comment,
|
| 'variables': recurseMap(variables),
|
| - 'functions': expandMethodMap(functions),
|
| + 'functions': _expandMethodMap(functions),
|
| 'classes': {
|
| 'class': classes.values.where((c) => c._isVisible)
|
| .map((e) => e.previewMap).toList(),
|
| @@ -1330,14 +1470,40 @@ class Library extends Indexable {
|
| }
|
|
|
| abstract class OwnedIndexable extends Indexable {
|
| + /// The object one scope-level above which this item is defined.
|
| + ///
|
| + /// Ex: The owner for a top level class, would be its enclosing library.
|
| + /// The owner of a local variable in a method would be the enclosing method.
|
| Indexable owner;
|
|
|
| + /// List of the meta annotations on this item.
|
| + List<Annotation> annotations;
|
| +
|
| /// Returns this object's qualified name, but following the conventions
|
| /// we're using in Dartdoc, which is that library names with dots in them
|
| /// have them replaced with hyphens.
|
| String get docName => owner.docName + '.' + mirror.simpleName;
|
|
|
| OwnedIndexable(DeclarationMirror mirror, this.owner) : super(mirror);
|
| +
|
| + /// Generates MDN comments from database.json.
|
| + String _mdnComment() {
|
| + //Check if MDN is loaded.
|
| + if (Indexable._mdn == null) {
|
| + // Reading in MDN related json file.
|
| + var root = _Generator._rootDirectory;
|
| + var mdnPath = path.join(root, 'utils/apidoc/mdn/database.json');
|
| + Indexable._mdn = JSON.decode(new File(mdnPath).readAsStringSync());
|
| + }
|
| + var domAnnotation = this.annotations.firstWhere(
|
| + (e) => e.mirror.qualifiedName == 'metadata.DomName',
|
| + orElse: () => null);
|
| + if (domAnnotation == null) return '';
|
| + var domName = domAnnotation.parameters.single;
|
| + var parts = domName.split('.');
|
| + if (parts.length == 2) return _mdnMemberComment(parts[0], parts[1]);
|
| + if (parts.length == 1) return _mdnTypeComment(parts[0]);
|
| + }
|
| }
|
|
|
| /// A class containing contents of a Dart class.
|
| @@ -1366,9 +1532,6 @@ class Class extends OwnedIndexable implements Comparable {
|
| Class superclass;
|
| bool isAbstract;
|
|
|
| - /// List of the meta annotations on the class.
|
| - List<Annotation> annotations;
|
| -
|
| /// Make sure that we don't check for inherited comments more than once.
|
| bool _commentsEnsured = false;
|
|
|
| @@ -1378,7 +1541,6 @@ class Class extends OwnedIndexable implements Comparable {
|
| var clazz = Indexable.getDocgenObject(mirror, owner);
|
| if (clazz is DummyMirror) {
|
| clazz = new Class._(mirror, owner);
|
| - entityMap[clazz.docName] = clazz;
|
| }
|
| return clazz;
|
| }
|
| @@ -1420,12 +1582,10 @@ class Class extends OwnedIndexable implements Comparable {
|
| isAbstract = classMirror.isAbstract;
|
| inheritedMethods = new Map<String, Method>();
|
|
|
| - // Tell all superclasses that you are a subclass, unless you are not
|
| + // Tell superclass that you are a subclass, unless you are not
|
| // visible or an intermediary mixin class.
|
| - if (!classMirror.isNameSynthetic && _isVisible) {
|
| - parentChain().forEach((parentClass) {
|
| - parentClass.addSubclass(this);
|
| - });
|
| + if (!classMirror.isNameSynthetic && _isVisible && superclass != null) {
|
| + superclass.addSubclass(this);
|
| }
|
|
|
| if (this.superclass != null) addInherited(superclass);
|
| @@ -1459,17 +1619,8 @@ class Class extends OwnedIndexable implements Comparable {
|
| return result == null ? super.findElementInScope(name) : result;
|
| }
|
|
|
| - markdown.Node fixReferenceWithScope(String name) => fixReference(name);
|
| -
|
| String get typeName => 'class';
|
|
|
| - /// Returns a list of all the parent classes.
|
| - List<Class> parentChain() {
|
| - // TODO(efortuna): Seems like we can get rid of this method.
|
| - var parent = superclass == null ? [] : [superclass];
|
| - return parent;
|
| - }
|
| -
|
| /// Add all inherited variables and methods from the provided superclass.
|
| /// If [_includePrivate] is true, it also adds the variables and methods from
|
| /// the superclass.
|
| @@ -1577,8 +1728,8 @@ class Class extends OwnedIndexable implements Comparable {
|
| .map((x) => x.qualifiedName).toList(),
|
| 'variables': recurseMap(variables),
|
| 'inheritedVariables': recurseMap(inheritedVariables),
|
| - 'methods': expandMethodMap(methods),
|
| - 'inheritedMethods': expandMethodMap(inheritedMethods),
|
| + 'methods': _expandMethodMap(methods),
|
| + 'inheritedMethods': _expandMethodMap(inheritedMethods),
|
| 'annotations': annotations.map((a) => a.toMap()).toList(),
|
| 'generics': recurseMap(generics)
|
| };
|
| @@ -1596,9 +1747,6 @@ class Typedef extends OwnedIndexable {
|
| /// Generic information about the typedef.
|
| Map<String, Generic> generics;
|
|
|
| - /// List of the meta annotations on the typedef.
|
| - List<Annotation> annotations;
|
| -
|
| /// Returns the [Library] for the given [mirror] if it has already been
|
| /// created, else creates it.
|
| factory Typedef(TypedefMirror mirror, Library owningLibrary) {
|
| @@ -1627,6 +1775,8 @@ class Typedef extends OwnedIndexable {
|
| 'generics': recurseMap(generics)
|
| };
|
|
|
| + markdown.Node fixReference(String name) => null;
|
| +
|
| String get typeName => 'typedef';
|
|
|
| bool _isValidMirror(DeclarationMirror mirror) => mirror is TypedefMirror;
|
| @@ -1641,9 +1791,6 @@ class Variable extends OwnedIndexable {
|
| Type type;
|
| String _variableName;
|
|
|
| - /// List of the meta annotations on the variable.
|
| - List<Annotation> annotations;
|
| -
|
| factory Variable(String variableName, VariableMirror mirror,
|
| Indexable owner) {
|
| var variable = Indexable.getDocgenObject(mirror);
|
| @@ -1688,8 +1835,6 @@ class Variable extends OwnedIndexable {
|
| return super.comment;
|
| }
|
|
|
| - markdown.Node fixReferenceWithScope(String name) => fixReference(name);
|
| -
|
| String findElementInScope(String name) {
|
| var lookupFunc = Indexable.determineLookupFunc(name);
|
| var result = lookupFunc(mirror, name);
|
| @@ -1726,10 +1871,7 @@ class Method extends OwnedIndexable {
|
| /// Qualified name to state where the comment is inherited from.
|
| String commentInheritedFrom = "";
|
|
|
| - /// List of the meta annotations on the method.
|
| - List<Annotation> annotations;
|
| -
|
| - factory Method(MethodMirror mirror, Indexable owner, // Indexable newOwner.
|
| + factory Method(MethodMirror mirror, Indexable owner,
|
| [Method methodInheritedFrom]) {
|
| var method = Indexable.getDocgenObject(mirror, owner);
|
| if (method is DummyMirror) {
|
| @@ -1753,8 +1895,6 @@ class Method extends OwnedIndexable {
|
| Method get originallyInheritedFrom => methodInheritedFrom == null ?
|
| this : methodInheritedFrom.originallyInheritedFrom;
|
|
|
| - markdown.Node fixReferenceWithScope(String name) => fixReference(name);
|
| -
|
| /// Look for the specified name starting with the current member, and
|
| /// progressively working outward to the current library scope.
|
| String findElementInScope(String name) {
|
| @@ -1838,14 +1978,16 @@ class Method extends OwnedIndexable {
|
| }
|
| var result = super.comment;
|
| if (result == '' && methodInheritedFrom != null) {
|
| - // this should be NOT from the MIRROR, but from the COMMENT
|
| + // This should be NOT from the MIRROR, but from the COMMENT.
|
| + methodInheritedFrom.comment; // Ensure comment field has been populated.
|
| _unresolvedComment = methodInheritedFrom._unresolvedComment;
|
|
|
| - var linkResolver = (name) => fixReferenceWithScope(name);
|
| + var linkResolver = (name) => fixReference(name);
|
| comment = _unresolvedComment == null ? '' :
|
| markdown.markdownToHtml(_unresolvedComment.trim(),
|
| linkResolver: linkResolver, inlineSyntaxes: _MARKDOWN_SYNTAXES);
|
| - commentInheritedFrom = methodInheritedFrom.commentInheritedFrom;
|
| + commentInheritedFrom = comment != '' ?
|
| + methodInheritedFrom.commentInheritedFrom : '';
|
| result = comment;
|
| }
|
| return result;
|
|
|