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

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

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

Powered by Google App Engine
This is Rietveld 408576698