Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(485)

Side by Side Diff: pkg/docgen/lib/docgen.dart

Issue 16975021: "Reverting 24208" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/docgen/example/test.dart ('k') | pkg/docgen/lib/src/dart2js_mirrors.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 /**
6 * The docgen tool takes in a library as input and produces documentation
7 * for the library as well as all libraries it imports and uses. The tool can
8 * be run by passing in the path to a .dart file like this:
9 *
10 * dart docgen.dart [OPTIONS] [FILE/DIR]
11 *
12 * This outputs information about all classes, variables, functions, and
13 * methods defined in the library and its imported libraries.
14 */
15 library docgen;
16
17 import 'dart:io';
18 import 'dart:json';
19 import 'dart:async';
20 import 'package:markdown/markdown.dart' as markdown;
21 import 'package:args/args.dart';
22 import 'dart2yaml.dart';
23 import 'package:compiler_unsupported/compiler.dart' as api;
24 import 'package:compiler_unsupported/implementation/filenames.dart';
25 import 'package:compiler_unsupported/implementation/mirrors/dart2js_mirror.dart'
26 as dart2js;
27 import 'package:compiler_unsupported/implementation/mirrors/mirrors.dart';
28 import 'package:compiler_unsupported/implementation/mirrors/mirrors_util.dart';
29 import 'package:compiler_unsupported/implementation/source_file_provider.dart';
30 import 'package:logging/logging.dart';
31
32 /// Logger for Dart Doc Generator.
33 var logger = new Logger("Docgen");
34
35 /// Unique ID, will get incremented everytime an ID is requested.
36 int _uid = 0;
37
38 int getID() => _uid++;
39
40 const String usage = "Usage: dart docgen.dart [OPTIONS] [FILE/DIR]";
41
42 /**
43 * Returns a ArgParser with all the flags and options created.
44 */
45 ArgParser initArgParser() {
46 var parser = new ArgParser();
47 parser.addFlag("help", abbr: "h",
48 help: "Prints help and usage information",
49 negatable: false,
50 callback: (help) {
51 if (help) print(parser.getUsage());
52 });
53 parser.addFlag("verbose", abbr: "v",
54 help: "Runs docgen with logging. ",
55 defaultsTo: false, negatable: false,
56 callback: (verbose) {
57 if (verbose) logger.onRecord.listen((record) => print(record.message));
58 });
59 parser.addFlag("yaml", abbr: "y",
60 help: "Outputs to YAML",
61 defaultsTo: true, negatable: true);
62 parser.addFlag("json", abbr: "j",
63 help: "Outputs to JSON",
64 defaultsTo: false, negatable: true);
65 parser.addFlag("hide-private",
66 help: "Hides private declarations" ,
67 defaultsTo: false, negatable: false);
68 parser.addFlag("sdk",
69 help: "Flag to parse SDK Library files",
70 defaultsTo: true, negatable: true);
71
72 return parser;
73 }
74
75 List<Path> listLibraries(List<String> args) {
76 if (args.length != 1) {
77 throw new UnsupportedError(usage);
78 }
79 var libraries = new List<Path>();
80 var type = FileSystemEntity.typeSync(args[0]);
81
82 if (type == FileSystemEntityType.NOT_FOUND) {
83 throw new UnsupportedError("File does not exist. $usage");
84 } else if (type == FileSystemEntityType.LINK) {
85 libraries.addAll(listLibrariesFromDir(new Link(args[0]).targetSync()));
86 } else if (type == FileSystemEntityType.FILE) {
87 libraries.add(new Path(args[0]));
88 logger.info("Added to libraries: ${libraries.last.toString()}");
89 } else if (type == FileSystemEntityType.DIRECTORY) {
90 libraries.addAll(listLibrariesFromDir(args[0]));
91 }
92 return libraries;
93 }
94
95 List<Path> listLibrariesFromDir(String path) {
96 var libraries = new List<Path>();
97 new Directory(path).listSync(recursive: true,
98 followLinks: true).forEach((file) {
99 if (new Path(file.path).extension == "dart") {
100 if (!file.path.contains("/packages/")) {
101 libraries.add(new Path(file.path));
102 logger.info("Added to libraries: ${libraries.last.toString()}");
103 }
104 }
105 });
106 return libraries;
107 }
108
109 /**
110 * This class documents a list of libraries.
111 */
112 class Docgen {
113
114 /// Libraries to be documented.
115 List<LibraryMirror> _libraries;
116
117 /// Saves list of libraries for Docgen object.
118 void set libraries(value) {
119 _libraries = value;
120 }
121
122 /// Current library being documented to be used for comment links.
123 LibraryMirror _currentLibrary;
124
125 /// Current class being documented to be used for comment links.
126 ClassMirror _currentClass;
127
128 /// Current member being documented to be used for comment links.
129 MemberMirror _currentMember;
130
131 /// Resolves reference links
132 markdown.Resolver linkResolver;
133
134 /// Should the output file type be YAML?
135 bool outputToYaml;
136 /// Should the output file type be JSON?
137 bool outputToJson;
138 /// Should the output file hide private declarations?
139 bool hidePrivate;
140 /// Should the output include SDK libraries?
141 bool sdk;
142
143 /**
144 * Docgen constructor initializes the link resolver for markdown parsing.
145 * Also initializes the command line arguments.
146 */
147 Docgen({ArgResults argResults}) {
148 outputToYaml = argResults["yaml"];
149 outputToJson = argResults["json"];
150 hidePrivate = argResults["hide-private"];
151 sdk = argResults["sdk"];
152
153 this.linkResolver = (name) =>
154 fixReference(name, _currentLibrary, _currentClass, _currentMember);
155 }
156
157 /**
158 * Analyzes set of libraries by getting a mirror system and triggers the
159 * documentation of the libraries.
160 */
161 void analyze(List<Path> libraries) {
162 /// Assuming the dart executable is from the Dart SDK folder.
163 var sdkRoot = new Path(new Options().executable).directoryPath
164 .directoryPath;
165 logger.info("SDK Root: ${sdkRoot.toString()}");
166 Path packageDir = libraries.last.directoryPath.append("packages");
167 logger.info("Package Root: ${packageDir.toString()}");
168 getMirrorSystem(libraries, sdkRoot,
169 packageRoot: packageDir).then((MirrorSystem mirrorSystem) {
170 if (mirrorSystem.libraries.values.isEmpty) {
171 throw new UnsupportedError("No Library Mirrors.");
172 }
173 this.libraries = mirrorSystem.libraries.values;
174 documentLibraries();
175 });
176 }
177
178 /**
179 * Analyzes set of libraries and provides a mirror system which can be used
180 * for static inspection of the source code.
181 */
182 Future<MirrorSystem> getMirrorSystem(List<Path> libraries,
183 Path libraryRoot, {Path packageRoot}) {
184 SourceFileProvider provider = new SourceFileProvider();
185 api.DiagnosticHandler diagnosticHandler =
186 new FormattingDiagnosticHandler(provider).diagnosticHandler;
187 Uri libraryUri = currentDirectory.resolve(appendSlash('$libraryRoot'));
188 Uri packageUri = null;
189 if (packageRoot != null) {
190 packageUri = currentDirectory.resolve(appendSlash('$packageRoot'));
191 }
192 List<Uri> librariesUri = <Uri>[];
193 libraries.forEach((library) {
194 librariesUri.add(currentDirectory.resolve(library.toString()));
195 });
196 return dart2js.analyze(librariesUri, libraryUri, packageUri,
197 provider.readStringFromUri, diagnosticHandler,
198 ['--preserve-comments', '--categories=Client,Server']);
199 }
200
201 /**
202 * Creates documentation for filtered libraries.
203 */
204 void documentLibraries() {
205 _libraries.forEach((library) {
206 // Files belonging to the SDK have a uri that begins with "dart:".
207 if (sdk || !library.uri.toString().startsWith("dart:")) {
208 _currentLibrary = library;
209 var result = new Library(library.qualifiedName, _getComment(library),
210 _getVariables(library.variables), _getMethods(library.functions),
211 _getClasses(library.classes), getID());
212 if (outputToJson) {
213 _writeToFile(stringify(result.toMap()), "${result.name}.json");
214 }
215 if (outputToYaml) {
216 _writeToFile(getYamlString(result.toMap()), "${result.name}.yaml");
217 }
218 }
219 });
220 }
221
222 /**
223 * Returns any documentation comments associated with a mirror with
224 * simple markdown converted to html.
225 */
226 String _getComment(DeclarationMirror mirror) {
227 String commentText;
228 mirror.metadata.forEach((metadata) {
229 if (metadata is CommentInstanceMirror) {
230 CommentInstanceMirror comment = metadata;
231 if (comment.isDocComment) {
232 if (commentText == null) {
233 commentText = comment.trimmedText;
234 } else {
235 commentText = "$commentText ${comment.trimmedText}";
236 }
237 }
238 }
239 });
240 commentText = commentText == null ? "" :
241 markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver)
242 .replaceAll("\n", "");
243 return commentText;
244 }
245
246 /**
247 * Converts all [_] references in comments to <code>_</code>.
248 */
249 // TODO(tmandel): Create proper links for [_] style markdown based
250 // on scope once layout of viewer is finished.
251 markdown.Node fixReference(String name, LibraryMirror currentLibrary,
252 ClassMirror currentClass, MemberMirror currentMember) {
253 return new markdown.Element.text('code', name);
254 }
255
256 /**
257 * Returns a map of [Variable] objects constructed from inputted mirrors.
258 */
259 Map<String, Variable> _getVariables(Map<String, VariableMirror> mirrorMap) {
260 var data = {};
261 mirrorMap.forEach((String mirrorName, VariableMirror mirror) {
262 if (!hidePrivate || !mirror.isPrivate) {
263 _currentMember = mirror;
264 data[mirrorName] = new Variable(mirrorName, mirror.isFinal,
265 mirror.isStatic, mirror.type.toString(), _getComment(mirror),
266 getID());
267 }
268 });
269 return data;
270 }
271
272 /**
273 * Returns a map of [Method] objects constructed from inputted mirrors.
274 */
275 Map<String, Method> _getMethods(Map<String, MethodMirror> mirrorMap) {
276 var data = {};
277 mirrorMap.forEach((String mirrorName, MethodMirror mirror) {
278 if (!hidePrivate || !mirror.isPrivate) {
279 _currentMember = mirror;
280 data[mirrorName] = new Method(mirrorName, mirror.isSetter,
281 mirror.isGetter, mirror.isConstructor, mirror.isOperator,
282 mirror.isStatic, mirror.returnType.toString(), _getComment(mirror),
283 _getParameters(mirror.parameters), getID());
284 }
285 });
286 return data;
287 }
288
289 /**
290 * Returns a map of [Class] objects constructed from inputted mirrors.
291 */
292 Map<String, Class> _getClasses(Map<String, ClassMirror> mirrorMap) {
293 var data = {};
294 mirrorMap.forEach((String mirrorName, ClassMirror mirror) {
295 if (!hidePrivate || !mirror.isPrivate) {
296 _currentClass = mirror;
297 var superclass = (mirror.superclass != null) ?
298 mirror.superclass.qualifiedName : "";
299 var interfaces =
300 mirror.superinterfaces.map((interface) => interface.qualifiedName);
301 data[mirrorName] = new Class(mirrorName, superclass, mirror.isAbstract,
302 mirror.isTypedef, _getComment(mirror), interfaces.toList(),
303 _getVariables(mirror.variables), _getMethods(mirror.methods),
304 getID());
305 }
306 });
307 return data;
308 }
309
310 /**
311 * Returns a map of [Parameter] objects constructed from inputted mirrors.
312 */
313 Map<String, Parameter> _getParameters(List<ParameterMirror> mirrorList) {
314 var data = {};
315 mirrorList.forEach((ParameterMirror mirror) {
316 _currentMember = mirror;
317 data[mirror.simpleName] = new Parameter(mirror.simpleName,
318 mirror.isOptional, mirror.isNamed, mirror.hasDefaultValue,
319 mirror.type.toString(), mirror.defaultValue, getID());
320 });
321 return data;
322 }
323 }
324
325 /**
326 * Transforms the map by calling toMap on each value in it.
327 */
328 Map recurseMap(Map inputMap) {
329 var outputMap = {};
330 inputMap.forEach((key, value) {
331 outputMap[key] = value.toMap();
332 });
333 return outputMap;
334 }
335
336 /**
337 * A class containing contents of a Dart library.
338 */
339 class Library {
340
341 /// Unique ID number for resolving links.
342 int id;
343
344 /// Documentation comment with converted markdown.
345 String comment;
346
347 /// Top-level variables in the library.
348 Map<String, Variable> variables;
349
350 /// Top-level functions in the library.
351 Map<String, Method> functions;
352
353 /// Classes defined within the library
354 Map<String, Class> classes;
355
356 String name;
357
358 Library(this.name, this.comment, this.variables,
359 this.functions, this.classes, this.id);
360
361 /// Generates a map describing the [Library] object.
362 Map toMap() {
363 var libraryMap = {};
364 libraryMap["id"] = id;
365 libraryMap["name"] = name;
366 libraryMap["comment"] = comment;
367 libraryMap["variables"] = recurseMap(variables);
368 libraryMap["functions"] = recurseMap(functions);
369 libraryMap["classes"] = recurseMap(classes);
370 return libraryMap;
371 }
372 }
373
374 /**
375 * A class containing contents of a Dart class.
376 */
377 // TODO(tmandel): Figure out how to do typedefs (what is needed)
378 class Class {
379
380 /// Unique ID number for resolving links.
381 int id;
382
383 /// Documentation comment with converted markdown.
384 String comment;
385
386 /// List of the names of interfaces that this class implements.
387 List<String> interfaces;
388
389 /// Top-level variables in the class.
390 Map<String, Variable> variables;
391
392 /// Methods in the class.
393 Map<String, Method> methods;
394
395 String name;
396 String superclass;
397 bool isAbstract;
398 bool isTypedef;
399
400 Class(this.name, this.superclass, this.isAbstract, this.isTypedef,
401 this.comment, this.interfaces, this.variables, this.methods, this.id);
402
403 /// Generates a map describing the [Class] object.
404 Map toMap() {
405 var classMap = {};
406 classMap["id"] = id;
407 classMap["name"] = name;
408 classMap["comment"] = comment;
409 classMap["superclass"] = superclass;
410 classMap["abstract"] = isAbstract.toString();
411 classMap["typedef"] = isTypedef.toString();
412 classMap["implements"] = new List.from(interfaces);
413 classMap["variables"] = recurseMap(variables);
414 classMap["methods"] = recurseMap(methods);
415 return classMap;
416 }
417 }
418
419 /**
420 * A class containing properties of a Dart variable.
421 */
422 class Variable {
423
424 /// Unique ID number for resolving links.
425 int id;
426
427 /// Documentation comment with converted markdown.
428 String comment;
429
430 String name;
431 bool isFinal;
432 bool isStatic;
433 String type;
434
435 Variable(this.name, this.isFinal, this.isStatic, this.type,
436 this.comment, this.id);
437
438 /// Generates a map describing the [Variable] object.
439 Map toMap() {
440 var variableMap = {};
441 variableMap["id"] = id;
442 variableMap["name"] = name;
443 variableMap["comment"] = comment;
444 variableMap["final"] = isFinal.toString();
445 variableMap["static"] = isStatic.toString();
446 variableMap["type"] = type;
447 return variableMap;
448 }
449 }
450
451 /**
452 * A class containing properties of a Dart method.
453 */
454 class Method {
455
456 /// Unique ID number for resolving links.
457 int id;
458
459 /// Documentation comment with converted markdown.
460 String comment;
461
462 /// Parameters for this method.
463 Map<String, Parameter> parameters;
464
465 String name;
466 bool isSetter;
467 bool isGetter;
468 bool isConstructor;
469 bool isOperator;
470 bool isStatic;
471 String returnType;
472
473 Method(this.name, this.isSetter, this.isGetter, this.isConstructor,
474 this.isOperator, this.isStatic, this.returnType, this.comment,
475 this.parameters, this.id);
476
477 /// Generates a map describing the [Method] object.
478 Map toMap() {
479 var methodMap = {};
480 methodMap["id"] = id;
481 methodMap["name"] = name;
482 methodMap["comment"] = comment;
483 methodMap["type"] = isSetter ? "setter" : isGetter ? "getter" :
484 isOperator ? "operator" : isConstructor ? "constructor" : "method";
485 methodMap["static"] = isStatic.toString();
486 methodMap["return"] = returnType;
487 methodMap["parameters"] = recurseMap(parameters);
488 return methodMap;
489 }
490 }
491
492 /**
493 * A class containing properties of a Dart method/function parameter.
494 */
495 class Parameter {
496
497 /// Unique ID number for resolving links.
498 int id;
499
500 String name;
501 bool isOptional;
502 bool isNamed;
503 bool hasDefaultValue;
504 String type;
505 String defaultValue;
506
507 Parameter(this.name, this.isOptional, this.isNamed, this.hasDefaultValue,
508 this.type, this.defaultValue, this.id);
509
510 /// Generates a map describing the [Parameter] object.
511 Map toMap() {
512 var parameterMap = {};
513 parameterMap["id"] = id;
514 parameterMap["name"] = name;
515 parameterMap["optional"] = isOptional.toString();
516 parameterMap["named"] = isNamed.toString();
517 parameterMap["default"] = hasDefaultValue.toString();
518 parameterMap["type"] = type;
519 parameterMap["value"] = defaultValue;
520 return parameterMap;
521 }
522 }
523
524 /**
525 * Writes text to a file in the 'docs' directory.
526 */
527 void _writeToFile(String text, String filename) {
528 Directory dir = new Directory('docs');
529 if (!dir.existsSync()) {
530 dir.createSync();
531 }
532 File file = new File('docs/$filename');
533 if (!file.existsSync()) {
534 file.createSync();
535 }
536 file.openSync();
537 file.writeAsString(text);
538 }
OLDNEW
« no previous file with comments | « pkg/docgen/example/test.dart ('k') | pkg/docgen/lib/src/dart2js_mirrors.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698