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

Side by Side Diff: lib/dartdoc/dartdoc.dart

Issue 10780030: Dartdoc and apidoc updated to use Path. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 5 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 | « no previous file | lib/dartdoc/file_util.dart » ('j') | lib/dartdoc/mirrors/dart2js_mirror.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /** 5 /**
6 * To generate docs for a library, run this script with the path to an 6 * To generate docs for a library, run this script with the path to an
7 * entrypoint .dart file, like: 7 * entrypoint .dart file, like:
8 * 8 *
9 * $ dart dartdoc.dart foo.dart 9 * $ dart dartdoc.dart foo.dart
10 * 10 *
11 * This will create a "docs" directory with the docs for your libraries. To 11 * This will create a "docs" directory with the docs for your libraries. To
12 * create these beautiful docs, dartdoc parses your library and every library 12 * create these beautiful docs, dartdoc parses your library and every library
13 * it imports (recursively). From each library, it parses all classes and 13 * it imports (recursively). From each library, it parses all classes and
14 * members, finds the associated doc comments and builds crosslinked docs from 14 * members, finds the associated doc comments and builds crosslinked docs from
15 * them. 15 * them.
16 */ 16 */
17 #library('dartdoc'); 17 #library('dartdoc');
18 18
19 #import('dart:io'); 19 #import('dart:io');
20 #import('dart:uri'); 20 #import('dart:uri');
21 #import('dart:json'); 21 #import('dart:json');
22 #import('mirrors/mirrors.dart'); 22 #import('mirrors/mirrors.dart');
23 #import('mirrors/mirrors_util.dart'); 23 #import('mirrors/mirrors_util.dart');
24 #import('mirrors/dart2js_mirror.dart', prefix: 'dart2js'); 24 #import('mirrors/dart2js_mirror.dart', prefix: 'dart2js');
25 #import('classify.dart'); 25 #import('classify.dart');
26 #import('markdown.dart', prefix: 'md'); 26 #import('markdown.dart', prefix: 'md');
27 #import('../compiler/implementation/dart2js.dart', prefix: 'dart2js');
28 #import('../compiler/implementation/scanner/scannerlib.dart', 27 #import('../compiler/implementation/scanner/scannerlib.dart',
29 prefix: 'dart2js'); 28 prefix: 'dart2js');
30 #import('file_util.dart');
31 29
32 #source('comment_map.dart'); 30 #source('comment_map.dart');
33 #source('utils.dart'); 31 #source('utils.dart');
34 32
35 /** 33 /**
36 * Generates completely static HTML containing everything you need to browse 34 * Generates completely static HTML containing everything you need to browse
37 * the docs. The only client side behavior is trivial stuff like syntax 35 * the docs. The only client side behavior is trivial stuff like syntax
38 * highlighting code. 36 * highlighting code.
39 */ 37 */
40 final MODE_STATIC = 0; 38 final MODE_STATIC = 0;
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
96 94
97 case '--omit-generation-time': 95 case '--omit-generation-time':
98 omitGenerationTime = true; 96 omitGenerationTime = true;
99 break; 97 break;
100 case '--verbose': 98 case '--verbose':
101 verbose = true; 99 verbose = true;
102 break; 100 break;
103 101
104 default: 102 default:
105 if (arg.startsWith('--out=')) { 103 if (arg.startsWith('--out=')) {
106 outputDir = arg.substring('--out='.length); 104 outputDir = arg.substring('--out='.length);
Bill Hesse 2012/07/17 13:42:13 Path?
Johnni Winther 2012/07/19 08:37:07 The type of outputDir is changed to Path.
107 } else { 105 } else {
108 print('Unknown option: $arg'); 106 print('Unknown option: $arg');
109 printUsage(); 107 printUsage();
110 return; 108 return;
111 } 109 }
112 break; 110 break;
113 } 111 }
114 } 112 }
115 113
116 if (args.length == 0) { 114 if (args.length == 0) {
117 print('Provide at least one dart file to process.'); 115 print('Provide at least one dart file to process.');
Bill Hesse 2012/07/17 13:42:13 "exactly one file"?
Johnni Winther 2012/07/19 08:37:07 Yes, currently. This is going to change soon. And
118 return; 116 return;
119 } 117 }
120 118
121 // TODO(rnystrom): Note that the following lines get munged by create-sdk to 119 final entrypoint = new Path.fromNative(args[args.length - 1]);
122 // work with the SDK's different file layout. If you change, be sure to test
123 // that dartdoc still works when run from the built SDK directory.
124 final String libPath = joinPaths(scriptDir, '../');
125
126 // The entrypoint of the library to generate docs for.
127 // TODO(johnniwinther): Handle absolute/relative paths
128 final entrypoint = canonicalizePath(args[args.length - 1]);
129 120
130 final dartdoc = new Dartdoc(); 121 final dartdoc = new Dartdoc();
131 122
132 if (includeSource != null) dartdoc.includeSource = includeSource; 123 if (includeSource != null) dartdoc.includeSource = includeSource;
133 if (mode != null) dartdoc.mode = mode; 124 if (mode != null) dartdoc.mode = mode;
134 if (outputDir != null) dartdoc.outputDir = outputDir; 125 if (outputDir != null) dartdoc.outputDir = new Path.fromNative(outputDir);
135 if (generateAppCache != null) dartdoc.generateAppCache = generateAppCache; 126 if (generateAppCache != null) dartdoc.generateAppCache = generateAppCache;
136 if (omitGenerationTime != null) { 127 if (omitGenerationTime != null) {
137 dartdoc.omitGenerationTime = omitGenerationTime; 128 dartdoc.omitGenerationTime = omitGenerationTime;
138 } 129 }
139 if (verbose != null) dartdoc.verbose = verbose; 130 if (verbose != null) dartdoc.verbose = verbose;
140 131
141 cleanOutputDirectory(dartdoc.outputDir); 132 cleanOutputDirectory(dartdoc.outputDir);
142 133
143 dartdoc.documentEntryPoint(entrypoint, libPath); 134 dartdoc.documentEntryPoint(entrypoint, libPath);
144 135
145 // Compile the client-side code to JS. 136 // Compile the client-side code to JS.
146 final clientScript = (dartdoc.mode == MODE_STATIC) ? 'static' : 'live-nav'; 137 final clientScript = (dartdoc.mode == MODE_STATIC) ? 'static' : 'live-nav';
147 compileScript( 138 Future compiled = compileScript(
148 '$scriptDir/client-$clientScript.dart', 139 scriptDir.append('client-$clientScript.dart'),
149 '${dartdoc.outputDir}/client-$clientScript.js'); 140 dartdoc.outputDir.append('client-$clientScript.js'));
150 141
151 final Future filesCopied = copyFiles('$scriptDir/static', dartdoc.outputDir); 142 Future filesCopied = copyFiles(scriptDir.append('static'), dartdoc.outputDir);
152 143
153 Futures.wait([filesCopied]).then((_) { 144 Futures.wait([compiled, filesCopied]).then((_) {
Bill Hesse 2012/07/17 13:42:13 I should start using _ as my "ignore" argument. S
Johnni Winther 2012/07/19 08:37:07 I think so.
154 print('Documented ${dartdoc._totalLibraries} libraries, ' 145 print('Documented ${dartdoc._totalLibraries} libraries, '
155 '${dartdoc._totalTypes} types, and ' 146 '${dartdoc._totalTypes} types, and '
156 '${dartdoc._totalMembers} members.'); 147 '${dartdoc._totalMembers} members.');
157 }); 148 });
158 } 149 }
159 150
160 void printUsage() { 151 void printUsage() {
161 print(''' 152 print('''
162 Usage dartdoc [options] <entrypoint> 153 Usage dartdoc [options] <entrypoint>
163 [options] include 154 [options] include
164 --no-code Do not include source code in the documentation. 155 --no-code Do not include source code in the documentation.
165 156
166 --mode=static Generates completely static HTML containing 157 --mode=static Generates completely static HTML containing
167 everything you need to browse the docs. The only 158 everything you need to browse the docs. The only
168 client side behavior is trivial stuff like syntax 159 client side behavior is trivial stuff like syntax
169 highlighting code. 160 highlighting code.
170 161
171 --mode=live-nav (default) Generated docs do not include baked HTML 162 --mode=live-nav (default) Generated docs do not include baked HTML
172 navigation. Instead, a single `nav.json` file is 163 navigation. Instead, a single `nav.json` file is
173 created and the appropriate navigation is generated 164 created and the appropriate navigation is generated
174 client-side by parsing that and building HTML. 165 client-side by parsing that and building HTML.
175 This dramatically reduces the generated size of 166 This dramatically reduces the generated size of
176 the HTML since a large fraction of each static page 167 the HTML since a large fraction of each static page
177 is just redundant navigation links. 168 is just redundant navigation links.
178 In this mode, the browser will do a XHR for 169 In this mode, the browser will do a XHR for
179 nav.json which means that to preview docs locally, 170 nav.json which means that to preview docs locally,
180 you will need to enable requesting file:// links in 171 you will need to enable requesting file:// links in
181 your browser or run a little local server like 172 your browser or run a little local server like
182 `python -m SimpleHTTPServer`. 173 `python -m SimpleHTTPServer`.
183 174
184 --generate-app-cache Generates the App Cache manifest file, enabling 175 --generate-app-cache Generates the App Cache manifest file, enabling
185 offline doc viewing. 176 offline doc viewing.
186 177
187 --out=<dir> Generates files into directory <dir>. If omitted 178 --out=<dir> Generates files into directory <dir>. If omitted
188 the files are generated into ./docs/ 179 the files are generated into ./docs/
189 180
190 --verbose Print verbose information during generation. 181 --verbose Print verbose information during generation.
191 '''); 182 ''');
192 } 183 }
193 184
194 /** 185 /**
195 * Gets the full path to the directory containing the entrypoint of the current 186 * Gets the full path to the directory containing the entrypoint of the current
196 * script. In other words, if you invoked dartdoc, directly, it will be the 187 * script. In other words, if you invoked dartdoc, directly, it will be the
197 * path to the directory containing `dartdoc.dart`. If you're running a script 188 * path to the directory containing `dartdoc.dart`. If you're running a script
198 * that imports dartdoc, it will be the path to that script. 189 * that imports dartdoc, it will be the path to that script.
199 */ 190 */
200 String get scriptDir() { 191 Path get scriptDir() {
Bill Hesse 2012/07/17 13:42:13 Lazy intialized statics work perfectly here, I thi
Johnni Winther 2012/07/19 08:37:07 This is not currently supported since current impl
Bill Hesse 2012/07/19 13:36:19 Can we write a TODO to fix this once they are supp
201 return dirname(new File(new Options().script).fullPathSync()); 192 return new Path.fromNative(new Options().script).directoryPath;
193 }
194
195 Path get libPath() {
196 // TODO(rnystrom): Note that the following lines get munged by create-sdk to
197 // work with the SDK's different file layout. If you change, be sure to test
198 // that dartdoc still works when run from the built SDK directory.
199 return scriptDir.append('../..');
Bill Hesse 2012/07/17 13:42:13 Can't we have a const flag or enum, munged by the
Johnni Winther 2012/07/19 08:37:07 Changed to use a bool IN_SDK flag.
202 } 200 }
203 201
204 /** 202 /**
205 * Deletes and recreates the output directory at [path] if it exists. 203 * Deletes and recreates the output directory at [path] if it exists.
206 */ 204 */
207 void cleanOutputDirectory(String path) { 205 void cleanOutputDirectory(Path path) {
208 final outputDir = new Directory(path); 206 final outputDir = new Directory.fromPath(path);
209 if (outputDir.existsSync()) { 207 if (outputDir.existsSync()) {
210 outputDir.deleteRecursivelySync(); 208 outputDir.deleteRecursivelySync();
211 } 209 }
212 210
213 try { 211 try {
214 // TODO(johnniwinther): Hack to avoid 'file already exists' exception thrown 212 // TODO(johnniwinther): Hack to avoid 'file already exists' exception thrown
215 // due to invalid result from dir.existsSync() (probably due to race 213 // due to invalid result from dir.existsSync() (probably due to race
216 // conditions). 214 // conditions).
Bill Hesse 2012/07/17 13:42:13 There is a bug for this - http://code.google.com/p
Johnni Winther 2012/07/19 08:37:07 Done.
217 outputDir.createSync(); 215 outputDir.createSync();
218 } catch (DirectoryIOException e) { 216 } catch (DirectoryIOException e) {
219 // Ignore. 217 // Ignore.
220 } 218 }
221 } 219 }
222 220
223 /** 221 /**
224 * Copies all of the files in the directory [from] to [to]. Does *not* 222 * Copies all of the files in the directory [from] to [to]. Does *not*
225 * recursively copy subdirectories. 223 * recursively copy subdirectories.
226 * 224 *
227 * Note: runs asynchronously, so you won't see any files copied until after the 225 * Note: runs asynchronously, so you won't see any files copied until after the
228 * event loop has had a chance to pump (i.e. after `main()` has returned). 226 * event loop has had a chance to pump (i.e. after `main()` has returned).
229 */ 227 */
230 Future copyFiles(String from, String to) { 228 Future copyFiles(Path from, Path to) {
Bill Hesse 2012/07/17 13:42:13 copyDirectory?
Johnni Winther 2012/07/19 08:37:07 Done.
231 final completer = new Completer(); 229 final completer = new Completer();
232 final fromDir = new Directory(from); 230 final fromDir = new Directory.fromPath(from);
233 final lister = fromDir.list(recursive: false); 231 final lister = fromDir.list(recursive: false);
234 232
235 lister.onFile = (path) { 233 lister.onFile = (String path) {
236 final name = basename(path); 234 final name = new Path.fromNative(path).filename;
237 // TODO(rnystrom): Hackish. Ignore 'hidden' files like .DS_Store. 235 // TODO(rnystrom): Hackish. Ignore 'hidden' files like .DS_Store.
238 if (name.startsWith('.')) return; 236 if (name.startsWith('.')) return;
239 237
240 new File(path).readAsBytes().then((bytes) { 238 new File(path).readAsBytes().then((bytes) {
Bill Hesse 2012/07/17 13:42:13 Copying should work better with File from; File to
Johnni Winther 2012/07/19 08:37:07 Done.
241 final outFile = new File('$to/$name'); 239 final outFile = new File.fromPath(to.append(name));
242 final stream = outFile.openOutputStream(FileMode.WRITE); 240 final stream = outFile.openOutputStream(FileMode.WRITE);
243 stream.write(bytes, copyBuffer: false); 241 stream.write(bytes, copyBuffer: false);
244 stream.close(); 242 stream.close();
245 }); 243 });
246 }; 244 };
247 lister.onDone = (done) => completer.complete(true); 245 lister.onDone = (done) => completer.complete(true);
248 return completer.future; 246 return completer.future;
249 } 247 }
250 248
251 /** 249 /**
252 * Compiles the given Dart script to a JavaScript file at [jsPath] using the 250 * Compiles the given Dart script to a JavaScript file at [jsPath] using the
253 * Dart2js compiler. 251 * Dart2js compiler.
254 */ 252 */
255 void compileScript(String dartPath, String jsPath) { 253 Future<bool> compileScript(Path dartPath, Path jsPath) {
256 dart2js.compile([ 254 var completer = new Completer<bool>();
257 '--no-colors', 255 var compilation = new Compilation(dartPath, libPath);
258 // TODO(johnniwinther): The following lines get munged by create-sdk to 256 Future<String> result = compilation.compileToJavaScript();
259 // work with the SDK's different file layout. If you change, be sure to 257 result.then((jsCode) {
260 // test that dartdoc still works when run from the built SDK directory. 258 writeString(new File.fromPath(jsPath), jsCode);
261 '--library-root=${joinPaths(scriptDir, '../../')}', 259 completer.complete(true);
262 '--out=$jsPath', 260 });
263 '--throw-on-error', 261 result.handleException((e) => completer.completeException(e));
264 '--suppress-warnings', 262 return completer.future;
265 dartPath]);
266 } 263 }
267 264
268 class Dartdoc { 265 class Dartdoc {
269 266
270 /** Set to `false` to not include the source code in the generated docs. */ 267 /** Set to `false` to not include the source code in the generated docs. */
271 bool includeSource = true; 268 bool includeSource = true;
272 269
273 /** 270 /**
274 * Dartdoc can generate docs in a few different ways based on how dynamic you 271 * Dartdoc can generate docs in a few different ways based on how dynamic you
275 * want the client-side behavior to be. The value for this should be one of 272 * want the client-side behavior to be. The value for this should be one of
276 * the `MODE_` constants. 273 * the `MODE_` constants.
277 */ 274 */
278 int mode = MODE_LIVE_NAV; 275 int mode = MODE_LIVE_NAV;
279 276
280 /** 277 /**
281 * Generates the App Cache manifest file, enabling offline doc viewing. 278 * Generates the App Cache manifest file, enabling offline doc viewing.
282 */ 279 */
283 bool generateAppCache = false; 280 bool generateAppCache = false;
284 281
285 /** Path to generate HTML files into. */ 282 /** Path to generate HTML files into. */
286 String outputDir = 'docs'; 283 Path outputDir = const Path('docs');
287 284
288 /** 285 /**
289 * The title used for the overall generated output. Set this to change it. 286 * The title used for the overall generated output. Set this to change it.
290 */ 287 */
291 String mainTitle = 'Dart Documentation'; 288 String mainTitle = 'Dart Documentation';
292 289
293 /** 290 /**
294 * The URL that the Dart logo links to. Defaults "index.html", the main 291 * The URL that the Dart logo links to. Defaults "index.html", the main
295 * page for the generated docs, but can be anything. 292 * page for the generated docs, but can be anything.
296 */ 293 */
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 /** The library that we're currently generating docs for. */ 327 /** The library that we're currently generating docs for. */
331 LibraryMirror _currentLibrary; 328 LibraryMirror _currentLibrary;
332 329
333 /** The type that we're currently generating docs for. */ 330 /** The type that we're currently generating docs for. */
334 InterfaceMirror _currentType; 331 InterfaceMirror _currentType;
335 332
336 /** The member that we're currently generating docs for. */ 333 /** The member that we're currently generating docs for. */
337 MemberMirror _currentMember; 334 MemberMirror _currentMember;
338 335
339 /** The path to the file currently being written to, relative to [outdir]. */ 336 /** The path to the file currently being written to, relative to [outdir]. */
340 String _filePath; 337 String _filePath;
Bill Hesse 2012/07/17 13:42:13 Make this a Path object?
Johnni Winther 2012/07/19 08:37:07 Done.
341 338
342 /** The file currently being written to. */ 339 /** The file currently being written to. */
343 StringBuffer _file; 340 StringBuffer _file;
344 341
345 int _totalLibraries = 0; 342 int _totalLibraries = 0;
346 int _totalTypes = 0; 343 int _totalTypes = 0;
347 int _totalMembers = 0; 344 int _totalMembers = 0;
348 345
349 Dartdoc() 346 Dartdoc()
350 : _comments = new CommentMap() { 347 : _comments = new CommentMap() {
351 // Patch in support for [:...:]-style code to the markdown parser. 348 // Patch in support for [:...:]-style code to the markdown parser.
352 // TODO(rnystrom): Markdown already has syntax for this. Phase this out? 349 // TODO(rnystrom): Markdown already has syntax for this. Phase this out?
353 md.InlineParser.syntaxes.insertRange(0, 1, 350 md.InlineParser.syntaxes.insertRange(0, 1,
354 new md.CodeSyntax(@'\[\:((?:.|\n)*?)\:\]')); 351 new md.CodeSyntax(@'\[\:((?:.|\n)*?)\:\]'));
355 352
356 md.setImplicitLinkResolver((name) => resolveNameReference(name, 353 md.setImplicitLinkResolver((name) => resolveNameReference(name,
357 library: _currentLibrary, type: _currentType, 354 currentLibrary: _currentLibrary, currentType: _currentType,
358 member: _currentMember)); 355 currentMember: _currentMember));
359 } 356 }
360 357
361 bool includeLibrary(LibraryMirror library) { 358 bool includeLibrary(LibraryMirror library) {
362 if (libraries != null) { 359 if (libraries != null) {
363 return libraries.indexOf(library.simpleName()) != -1; 360 return libraries.indexOf(library.simpleName()) != -1;
364 } 361 }
365 return true; 362 return true;
366 } 363 }
367 364
368 String get footerContent(){ 365 String get footerContent(){
369 var footerItems = []; 366 var footerItems = [];
370 if(!omitGenerationTime) { 367 if(!omitGenerationTime) {
371 footerItems.add("This page was generated at ${new Date.now()}"); 368 footerItems.add("This page was generated at ${new Date.now()}");
372 } 369 }
373 if(footerText != null) { 370 if(footerText != null) {
374 footerItems.add(footerText); 371 footerItems.add(footerText);
375 } 372 }
376 var content = ''; 373 var content = '';
377 for (int i = 0; i < footerItems.length; i++) { 374 for (int i = 0; i < footerItems.length; i++) {
378 if(i > 0){ 375 if(i > 0){
379 content = content.concat('\n'); 376 content = content.concat('\n');
380 } 377 }
381 content = content.concat('<div>${footerItems[i]}</div>'); 378 content = content.concat('<div>${footerItems[i]}</div>');
382 } 379 }
383 return content; 380 return content;
384 } 381 }
385 382
386 void documentEntryPoint(String entrypoint, String libPath) { 383 void documentEntryPoint(Path entrypoint, Path libPath) {
387 final compilation = new Compilation(entrypoint, libPath); 384 final compilation = new Compilation(entrypoint, libPath);
388 _document(compilation); 385 _document(compilation);
389 } 386 }
390 387
391 void documentLibraries(List<String> libraries, String libPath) { 388 void documentLibraries(List<Path> libraryList, Path libPath) {
392 final compilation = new Compilation.library(libraries, libPath); 389 final compilation = new Compilation.library(libraryList, libPath);
393 _document(compilation); 390 _document(compilation);
394 } 391 }
395 392
396 void _document(Compilation compilation) { 393 void _document(Compilation compilation) {
397 // Sort the libraries by name (not key). 394 // Sort the libraries by name (not key).
398 _sortedLibraries = new List<LibraryMirror>.from( 395 _sortedLibraries = new List<LibraryMirror>.from(
399 compilation.mirrors().libraries().getValues().filter(includeLibrary)); 396 compilation.mirrors().libraries().getValues().filter(includeLibrary));
400 _sortedLibraries.sort((x, y) { 397 _sortedLibraries.sort((x, y) {
401 return x.simpleName().toUpperCase().compareTo( 398 return x.simpleName().toUpperCase().compareTo(
402 y.simpleName().toUpperCase()); 399 y.simpleName().toUpperCase());
403 }); 400 });
404 401
405 // Generate the docs. 402 // Generate the docs.
406 if (mode == MODE_LIVE_NAV) docNavigationJson(); 403 if (mode == MODE_LIVE_NAV) docNavigationJson();
407 404
408 docIndex(); 405 docIndex();
409 for (final library in _sortedLibraries) { 406 for (final library in _sortedLibraries) {
410 docLibrary(library); 407 docLibrary(library);
411 } 408 }
412 409
413 if (generateAppCache) { 410 if (generateAppCache) {
414 generateAppCacheManifest(); 411 generateAppCacheManifest();
415 } 412 }
416 } 413 }
417 414
418 void startFile(String path) { 415 void startFile(String path) {
419 _filePath = path; 416 _filePath = path;
Bill Hesse 2012/07/17 13:42:13 I see that it is convenient to have startFile take
Johnni Winther 2012/07/19 08:37:07 Done.
420 _file = new StringBuffer(); 417 _file = new StringBuffer();
421 } 418 }
422 419
423 void endFile() { 420 void endFile() {
424 final outPath = '$outputDir/$_filePath'; 421 final outPath = outputDir.join(new Path.fromNative(_filePath));
425 final dir = new Directory(dirname(outPath)); 422 final dir = new Directory.fromPath(outPath.directoryPath);
426 if (!dir.existsSync()) { 423 if (!dir.existsSync()) {
427 // TODO(johnniwinther): Hack to avoid 'file already exists' exception 424 // TODO(johnniwinther): Hack to avoid 'file already exists' exception
Bill Hesse 2012/07/17 13:42:13 TODO(3914): There is a bug for this issue: http://
428 // thrown due to invalid result from dir.existsSync() (probably due to 425 // thrown due to invalid result from dir.existsSync() (probably due to
429 // race conditions). 426 // race conditions).
430 try { 427 try {
431 dir.createSync(); 428 dir.createSync();
432 } catch (DirectoryIOException e) { 429 } catch (DirectoryIOException e) {
433 // Ignore. 430 // Ignore.
434 } 431 }
435 } 432 }
436 433
437 writeString(new File(outPath), _file.toString()); 434 writeString(new File.fromPath(outPath), _file.toString());
438 _filePath = null; 435 _filePath = null;
439 _file = null; 436 _file = null;
440 } 437 }
441 438
442 void write(String s) { 439 void write(String s) {
443 _file.add(s); 440 _file.add(s);
444 } 441 }
445 442
446 void writeln(String s) { 443 void writeln(String s) {
447 write(s); 444 write(s);
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
588 docLibraryNavigationJson(library, libraryMap); 585 docLibraryNavigationJson(library, libraryMap);
589 } 586 }
590 587
591 writeln(JSON.stringify(libraryMap)); 588 writeln(JSON.stringify(libraryMap));
592 endFile(); 589 endFile();
593 } 590 }
594 591
595 void docLibraryNavigationJson(LibraryMirror library, Map libraryMap) { 592 void docLibraryNavigationJson(LibraryMirror library, Map libraryMap) {
596 final types = []; 593 final types = [];
597 594
598 for (final type in orderByName(library.types().getValues())) { 595 for (InterfaceMirror type in orderByName(library.types().getValues())) {
599 if (type.isPrivate) continue; 596 if (type.isPrivate) continue;
600 597
601 final kind = type.isClass ? 'class' : 'interface'; 598 final kind = type.isClass ? 'class' : 'interface';
602 final url = typeUrl(type); 599 final url = typeUrl(type);
603 types.add({ 'name': typeName(type), 'kind': kind, 'url': url }); 600 types.add({ 'name': typeName(type), 'kind': kind, 'url': url });
604 } 601 }
605 602
606 libraryMap[library.simpleName()] = types; 603 libraryMap[library.simpleName()] = types;
607 } 604 }
608 605
(...skipping 21 matching lines...) Expand all
630 627
631 writeln('</div>'); 628 writeln('</div>');
632 } 629 }
633 630
634 /** Writes the navigation for the types contained by the given library. */ 631 /** Writes the navigation for the types contained by the given library. */
635 void docLibraryNavigation(LibraryMirror library) { 632 void docLibraryNavigation(LibraryMirror library) {
636 // Show the exception types separately. 633 // Show the exception types separately.
637 final types = <InterfaceMirror>[]; 634 final types = <InterfaceMirror>[];
638 final exceptions = <InterfaceMirror>[]; 635 final exceptions = <InterfaceMirror>[];
639 636
640 for (final type in orderByName(library.types().getValues())) { 637 for (InterfaceMirror type in orderByName(library.types().getValues())) {
641 if (type.isPrivate) continue; 638 if (type.isPrivate) continue;
642 639
643 if (isException(type)) { 640 if (isException(type)) {
644 exceptions.add(type); 641 exceptions.add(type);
645 } else { 642 } else {
646 types.add(type); 643 types.add(type);
647 } 644 }
648 } 645 }
649 646
650 if ((types.length == 0) && (exceptions.length == 0)) return; 647 if ((types.length == 0) && (exceptions.length == 0)) return;
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
695 } 692 }
696 693
697 // Document the top-level members. 694 // Document the top-level members.
698 docMembers(library); 695 docMembers(library);
699 696
700 // Document the types. 697 // Document the types.
701 final classes = <InterfaceMirror>[]; 698 final classes = <InterfaceMirror>[];
702 final interfaces = <InterfaceMirror>[]; 699 final interfaces = <InterfaceMirror>[];
703 final exceptions = <InterfaceMirror>[]; 700 final exceptions = <InterfaceMirror>[];
704 701
705 for (final type in orderByName(library.types().getValues())) { 702 for (InterfaceMirror type in orderByName(library.types().getValues())) {
706 if (type.isPrivate) continue; 703 if (type.isPrivate) continue;
707 704
708 if (isException(type)) { 705 if (isException(type)) {
709 exceptions.add(type); 706 exceptions.add(type);
710 } else if (type.isClass) { 707 } else if (type.isClass) {
711 classes.add(type); 708 classes.add(type);
712 } else { 709 } else {
713 interfaces.add(type); 710 interfaces.add(type);
714 } 711 }
715 } 712 }
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after
945 } 942 }
946 } 943 }
947 944
948 void docMembers(ObjectMirror host) { 945 void docMembers(ObjectMirror host) {
949 // Collect the different kinds of members. 946 // Collect the different kinds of members.
950 final staticMethods = []; 947 final staticMethods = [];
951 final staticFields = []; 948 final staticFields = [];
952 final instanceMethods = []; 949 final instanceMethods = [];
953 final instanceFields = []; 950 final instanceFields = [];
954 951
955 for (final member in orderByName(host.declaredMembers().getValues())) { 952 for (MemberMirror member in orderByName(host.declaredMembers().getValues())) {
956 if (member.isPrivate) continue; 953 if (member.isPrivate) continue;
957 954
958 final methods = member.isStatic ? staticMethods : instanceMethods; 955 final methods = member.isStatic ? staticMethods : instanceMethods;
959 final fields = member.isStatic ? staticFields : instanceFields; 956 final fields = member.isStatic ? staticFields : instanceFields;
960 957
961 if (member.isMethod) { 958 if (member.isMethod) {
962 methods.add(member); 959 methods.add(member);
963 } else if (member.isField) { 960 } else if (member.isField) {
964 fields.add(member); 961 fields.add(member);
965 } 962 }
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after
1371 // Syntax highlight. 1368 // Syntax highlight.
1372 return classifySource(code); 1369 return classifySource(code);
1373 } 1370 }
1374 1371
1375 /** 1372 /**
1376 * This will be called whenever a doc comment hits a `[name]` in square 1373 * This will be called whenever a doc comment hits a `[name]` in square
1377 * brackets. It will try to figure out what the name refers to and link or 1374 * brackets. It will try to figure out what the name refers to and link or
1378 * style it appropriately. 1375 * style it appropriately.
1379 */ 1376 */
1380 md.Node resolveNameReference(String name, 1377 md.Node resolveNameReference(String name,
1381 [MemberMirror member = null, 1378 [MemberMirror currentMember = null,
1382 ObjectMirror type = null, 1379 ObjectMirror currentType = null,
1383 LibraryMirror library = null]) { 1380 LibraryMirror currentLibrary = null]) {
1384 makeLink(String href) { 1381 makeLink(String href) {
1385 final anchor = new md.Element.text('a', name); 1382 final anchor = new md.Element.text('a', name);
1386 anchor.attributes['href'] = relativePath(href); 1383 anchor.attributes['href'] = relativePath(href);
1387 anchor.attributes['class'] = 'crossref'; 1384 anchor.attributes['class'] = 'crossref';
1388 return anchor; 1385 return anchor;
1389 } 1386 }
1390 1387
1391 // See if it's a parameter of the current method. 1388 // See if it's a parameter of the current method.
1392 if (member is MethodMirror) { 1389 if (currentMember is MethodMirror) {
1393 for (final parameter in member.parameters()) { 1390 for (final parameter in currentMember.parameters()) {
1394 if (parameter.simpleName() == name) { 1391 if (parameter.simpleName() == name) {
1395 final element = new md.Element.text('span', name); 1392 final element = new md.Element.text('span', name);
1396 element.attributes['class'] = 'param'; 1393 element.attributes['class'] = 'param';
1397 return element; 1394 return element;
1398 } 1395 }
1399 } 1396 }
1400 } 1397 }
1401 1398
1402 // See if it's another member of the current type. 1399 // See if it's another member of the current type.
1403 if (type != null) { 1400 if (currentType != null) {
1404 final member = findMirror(type.declaredMembers(), name); 1401 final foundMember = findMirror(currentType.declaredMembers(), name);
1405 if (member != null) { 1402 if (foundMember != null) {
1406 return makeLink(memberUrl(member)); 1403 return makeLink(memberUrl(foundMember));
1407 } 1404 }
1408 } 1405 }
1409 1406
1410 // See if it's another type or a member of another type in the current 1407 // See if it's another type or a member of another type in the current
1411 // library. 1408 // library.
1412 if (library != null) { 1409 if (currentLibrary != null) {
1413 // See if it's a constructor 1410 // See if it's a constructor
1414 final constructorLink = (() { 1411 final constructorLink = (() {
1415 final match = 1412 final match =
1416 new RegExp(@'new ([\w$]+)(?:\.([\w$]+))?').firstMatch(name); 1413 new RegExp(@'new ([\w$]+)(?:\.([\w$]+))?').firstMatch(name);
1417 if (match == null) return; 1414 if (match == null) return;
1418 final type = findMirror(library.types(), match[1]); 1415 InterfaceMirror foundtype = findMirror(currentLibrary.types(), match[1]) ;
1419 if (type == null) return; 1416 if (foundtype == null) return;
1420 final constructor = 1417 final constructor =
1421 findMirror(type.constructors(), 1418 findMirror(foundtype.constructors(),
1422 match[2] == null ? '' : match[2]); 1419 match[2] == null ? '' : match[2]);
1423 if (constructor == null) return; 1420 if (constructor == null) return;
1424 return makeLink(memberUrl(constructor)); 1421 return makeLink(memberUrl(constructor));
1425 })(); 1422 })();
1426 if (constructorLink != null) return constructorLink; 1423 if (constructorLink != null) return constructorLink;
1427 1424
1428 // See if it's a member of another type 1425 // See if it's a member of another type
1429 final foreignMemberLink = (() { 1426 final foreignMemberLink = (() {
1430 final match = new RegExp(@'([\w$]+)\.([\w$]+)').firstMatch(name); 1427 final match = new RegExp(@'([\w$]+)\.([\w$]+)').firstMatch(name);
1431 if (match == null) return; 1428 if (match == null) return;
1432 final type = findMirror(library.types(), match[1]); 1429 InterfaceMirror foundtype = findMirror(currentLibrary.types(), match[1]) ;
1433 if (type == null) return; 1430 if (foundtype == null) return;
1434 final member = findMirror(type.declaredMembers(), match[2]); 1431 MemberMirror foundMember = findMirror(foundtype.declaredMembers(), match [2]);
1435 if (member == null) return; 1432 if (foundMember == null) return;
1436 return makeLink(memberUrl(member)); 1433 return makeLink(memberUrl(foundMember));
1437 })(); 1434 })();
1438 if (foreignMemberLink != null) return foreignMemberLink; 1435 if (foreignMemberLink != null) return foreignMemberLink;
1439 1436
1440 final type = findMirror(library.types(), name); 1437 InterfaceMirror foundType = findMirror(currentLibrary.types(), name);
1441 if (type != null) { 1438 if (foundType != null) {
1442 return makeLink(typeUrl(type)); 1439 return makeLink(typeUrl(foundType));
1443 } 1440 }
1444 1441
1445 // See if it's a top-level member in the current library. 1442 // See if it's a top-level member in the current library.
1446 final member = findMirror(library.declaredMembers(), name); 1443 MemberMirror foundMember = findMirror(currentLibrary.declaredMembers(), na me);
1447 if (member != null) { 1444 if (foundMember != null) {
1448 return makeLink(memberUrl(member)); 1445 return makeLink(memberUrl(foundMember));
1449 } 1446 }
1450 } 1447 }
1451 1448
1452 // TODO(rnystrom): Should also consider: 1449 // TODO(rnystrom): Should also consider:
1453 // * Names imported by libraries this library imports. 1450 // * Names imported by libraries this library imports.
1454 // * Type parameters of the enclosing type. 1451 // * Type parameters of the enclosing type.
1455 1452
1456 return new md.Element.text('code', name); 1453 return new md.Element.text('code', name);
1457 } 1454 }
1458 1455
1459 generateAppCacheManifest() { 1456 generateAppCacheManifest() {
1460 print('Generating app cache manifest from output $outputDir'); 1457 print('Generating app cache manifest from output $outputDir');
1461 startFile('appcache.manifest'); 1458 startFile('appcache.manifest');
1462 write("CACHE MANIFEST\n\n"); 1459 write("CACHE MANIFEST\n\n");
1463 write("# VERSION: ${new Date.now()}\n\n"); 1460 write("# VERSION: ${new Date.now()}\n\n");
1464 write("NETWORK:\n*\n\n"); 1461 write("NETWORK:\n*\n\n");
1465 write("CACHE:\n"); 1462 write("CACHE:\n");
1466 var toCache = new Directory(outputDir); 1463 var toCache = new Directory.fromPath(outputDir);
1467 var pathPrefix = new File(outputDir).fullPathSync(); 1464 var pathPrefix = new File.fromPath(outputDir).fullPathSync();
1468 var pathPrefixLength = pathPrefix.length; 1465 var pathPrefixLength = pathPrefix.length;
1469 toCache.onFile = (filename) { 1466 var toCacheLister = toCache.list(recursive: true);
1467 toCacheLister.onFile = (filename) {
1470 if (filename.endsWith('appcache.manifest')) { 1468 if (filename.endsWith('appcache.manifest')) {
1471 return; 1469 return;
1472 } 1470 }
Bill Hesse 2012/07/17 13:42:13 var relativePath = new Path.fromNative(filename).r
Johnni Winther 2012/07/19 08:37:07 Changed, but a lot of new issues arose. Check the
1473 var relativePath = filename.substring(pathPrefixLength + 1); 1471 var relativePath = filename.substring(pathPrefixLength + 1);
1474 write("$relativePath\n"); 1472 write("$relativePath\n");
1475 }; 1473 };
1476 toCache.onDone = (done) => endFile(); 1474 toCacheLister.onDone = (done) => endFile();
1477 toCache.list(recursive: true);
1478 } 1475 }
1479 1476
1480 /** 1477 /**
1481 * Returns [:true:] if [type] should be regarded as an exception. 1478 * Returns [:true:] if [type] should be regarded as an exception.
1482 */ 1479 */
1483 bool isException(TypeMirror type) { 1480 bool isException(TypeMirror type) {
1484 return type.simpleName().endsWith('Exception'); 1481 return type.simpleName().endsWith('Exception');
1485 } 1482 }
1486 } 1483 }
1487 1484
OLDNEW
« no previous file with comments | « no previous file | lib/dartdoc/file_util.dart » ('j') | lib/dartdoc/mirrors/dart2js_mirror.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698