119b2d58ce
BUG= R=terry@google.com Review-Url: https://codereview.chromium.org/2827793002 .
198 lines
6.1 KiB
Dart
198 lines
6.1 KiB
Dart
// Copyright (c) 2013, 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.
|
|
|
|
/**
|
|
* A library for extracting the documentation from the various HTML libraries
|
|
* ([dart:html], [dart:svg], [dart:web_audio], [dart:indexed_db]) and saving
|
|
* those documentation comments to a JSON file.
|
|
*/
|
|
|
|
library docs;
|
|
|
|
import '../../../../sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart';
|
|
import '../../../../pkg/compiler/lib/src/mirrors/source_mirrors.dart';
|
|
import '../../../../pkg/compiler/lib/src/mirrors/mirrors_util.dart';
|
|
import '../../../../sdk/lib/_internal/dartdoc/lib/dartdoc.dart';
|
|
import '../../../../sdk/lib/_internal/dartdoc/lib/src/json_serializer.dart';
|
|
import '../../../../utils/apidoc/lib/metadata.dart';
|
|
import 'dart:async';
|
|
import 'dart:io';
|
|
|
|
/// The various HTML libraries.
|
|
const List<String> HTML_LIBRARY_NAMES = const [
|
|
'dart:html',
|
|
'dart:indexed_db',
|
|
'dart:svg',
|
|
'dart:web_audio',
|
|
'dart:web_gl',
|
|
'dart:web_sql'
|
|
];
|
|
/**
|
|
* Converts the libraries in [HTML_LIBRARY_NAMES] to a json file at [jsonPath]
|
|
* given the library path at [libUri].
|
|
*
|
|
* The json output looks like:
|
|
* {
|
|
* $library_name: {
|
|
* $interface_name: {
|
|
* comment: "$comment"
|
|
* members: {
|
|
* $member: [
|
|
* [$comment1line1,
|
|
* $comment1line2,
|
|
* ...],
|
|
* ...
|
|
* ],
|
|
* ...
|
|
* }
|
|
* },
|
|
* ...
|
|
* },
|
|
* ...
|
|
* }
|
|
*
|
|
* Completes to true if any errors were encountered, false otherwise.
|
|
*/
|
|
Future<bool> convert(String libUri, String jsonPath) {
|
|
var paths = <String>[];
|
|
for (var libraryName in HTML_LIBRARY_NAMES) {
|
|
paths.add(libraryName);
|
|
}
|
|
|
|
return analyze(paths, libUri, options: ['--preserve-comments'])
|
|
.then((MirrorSystem mirrors) {
|
|
var convertedJson = _generateJsonFromLibraries(mirrors);
|
|
return _exportJsonToFile(convertedJson, jsonPath);
|
|
});
|
|
}
|
|
|
|
Future<bool> _exportJsonToFile(Map convertedJson, String jsonPath) {
|
|
return new Future.sync(() {
|
|
final jsonFile = new File(jsonPath);
|
|
var writeJson = prettySerialize(convertedJson);
|
|
|
|
var outputStream = jsonFile.openWrite();
|
|
outputStream.writeln(writeJson);
|
|
outputStream.close();
|
|
return outputStream.done.then((_) => false);
|
|
});
|
|
}
|
|
|
|
Map _generateJsonFromLibraries(MirrorSystem mirrors) {
|
|
var convertedJson = {};
|
|
|
|
// Sort the libraries by name (not key).
|
|
var sortedLibraries = new List<LibraryMirror>.from(mirrors.libraries.values
|
|
.where((e) => HTML_LIBRARY_NAMES.indexOf(e.uri.toString()) >= 0))
|
|
..sort((x, y) => x.uri
|
|
.toString()
|
|
.toUpperCase()
|
|
.compareTo(y.uri.toString().toUpperCase()));
|
|
|
|
for (LibraryMirror libMirror in sortedLibraries) {
|
|
print('Extracting documentation from ${libMirror.simpleName}.');
|
|
|
|
var libraryJson = {};
|
|
var sortedClasses = _sortAndFilterMirrors(
|
|
classesOf(libMirror.declarations).toList(),
|
|
ignoreDocsEditable: true);
|
|
|
|
for (ClassMirror classMirror in sortedClasses) {
|
|
print(' class: $classMirror');
|
|
var classJson = {};
|
|
var sortedMembers =
|
|
_sortAndFilterMirrors(membersOf(classMirror.declarations).toList());
|
|
|
|
var membersJson = {};
|
|
for (var memberMirror in sortedMembers) {
|
|
print(' member: $memberMirror');
|
|
var memberDomName = domNames(memberMirror)[0];
|
|
var memberComment = _splitCommentsByNewline(
|
|
computeUntrimmedCommentAsList(memberMirror));
|
|
|
|
// Remove interface name from Dom Name.
|
|
if (memberDomName.indexOf('.') >= 0) {
|
|
memberDomName =
|
|
memberDomName.substring(memberDomName.indexOf('.') + 1);
|
|
}
|
|
|
|
if (!memberComment.isEmpty) {
|
|
membersJson.putIfAbsent(memberDomName, () => memberComment);
|
|
}
|
|
}
|
|
|
|
// Only include the comment if DocsEditable is set.
|
|
var classComment =
|
|
_splitCommentsByNewline(computeUntrimmedCommentAsList(classMirror));
|
|
if (!classComment.isEmpty &&
|
|
findMetadata(classMirror.metadata, 'DocsEditable') != null) {
|
|
classJson.putIfAbsent('comment', () => classComment);
|
|
}
|
|
if (!membersJson.isEmpty) {
|
|
classJson.putIfAbsent('members', () => membersJson);
|
|
}
|
|
|
|
if (!classJson.isEmpty) {
|
|
libraryJson.putIfAbsent(domNames(classMirror)[0], () => classJson);
|
|
}
|
|
}
|
|
|
|
if (!libraryJson.isEmpty) {
|
|
convertedJson.putIfAbsent(nameOf(libMirror), () => libraryJson);
|
|
}
|
|
}
|
|
|
|
return convertedJson;
|
|
}
|
|
|
|
/// Filter out mirrors that are private, or which are not part of this docs
|
|
/// process. That is, ones without the DocsEditable annotation.
|
|
/// If [ignoreDocsEditable] is true, relax the restriction on @DocsEditable().
|
|
/// This is to account for classes that are defined in a template, but whose
|
|
/// members are generated.
|
|
List<DeclarationMirror> _sortAndFilterMirrors(List<DeclarationMirror> mirrors,
|
|
{ignoreDocsEditable: false}) {
|
|
var filteredMirrors = mirrors
|
|
.where((DeclarationMirror c) =>
|
|
!domNames(c).isEmpty &&
|
|
!displayName(c).startsWith('_') &&
|
|
(!ignoreDocsEditable
|
|
? (findMetadata(c.metadata, 'DocsEditable') != null)
|
|
: true))
|
|
.toList();
|
|
|
|
filteredMirrors.sort((x, y) =>
|
|
domNames(x)[0].toUpperCase().compareTo(domNames(y)[0].toUpperCase()));
|
|
|
|
return filteredMirrors;
|
|
}
|
|
|
|
List<String> _splitCommentsByNewline(List<String> comments) {
|
|
var out = [];
|
|
|
|
comments.forEach((c) {
|
|
out.addAll(c.split(new RegExp('\n')));
|
|
});
|
|
|
|
return out;
|
|
}
|
|
|
|
/// Given the class mirror, returns the names found or an empty list.
|
|
List<String> domNames(DeclarationMirror mirror) {
|
|
var domNameMetadata = findMetadata(mirror.metadata, 'DomName');
|
|
|
|
if (domNameMetadata != null) {
|
|
var domNames = <String>[];
|
|
var tags = domNameMetadata.getField(#name);
|
|
for (var s in tags.reflectee.split(',')) {
|
|
domNames.add(s.trim());
|
|
}
|
|
|
|
if (domNames.length == 1 && domNames[0] == 'none') return <String>[];
|
|
return domNames;
|
|
} else {
|
|
return <String>[];
|
|
}
|
|
}
|