OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library docgen.generator; | 5 library docgen.generator; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:collection'; | 8 import 'dart:collection'; |
9 import 'dart:convert'; | 9 import 'dart:convert'; |
10 import 'dart:io'; | 10 import 'dart:io'; |
11 | 11 |
12 import 'package:markdown/markdown.dart' as markdown; | 12 import 'package:markdown/markdown.dart' as markdown; |
13 import 'package:path/path.dart' as path; | 13 import 'package:path/path.dart' as path; |
14 | 14 |
15 import '../../../../sdk/lib/_internal/compiler/compiler.dart' as api; | 15 import '../../../../sdk/lib/_internal/compiler/compiler.dart' as api; |
16 import '../../../../sdk/lib/_internal/compiler/implementation/filenames.dart'; | 16 import '../../../../sdk/lib/_internal/compiler/implementation/filenames.dart'; |
17 import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/analyze.da
rt' | 17 import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/analyze.da
rt' |
18 as dart2js; | 18 as dart2js; |
19 import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mi
rrors.dart' | 19 import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mi
rrors.dart' |
20 as dart2js_mirrors; | 20 as dart2js_mirrors; |
21 import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_ut
il.dart' | 21 import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_ut
il.dart' |
22 as dart2js_util; | 22 as dart2js_util; |
23 import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mir
rors.dart'; | 23 import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mir
rors.dart'; |
24 import '../../../../sdk/lib/_internal/compiler/implementation/source_file_provid
er.dart'; | 24 import '../../../../sdk/lib/_internal/compiler/implementation/source_file_provid
er.dart'; |
25 import '../../../../sdk/lib/_internal/libraries.dart'; | 25 import '../../../../sdk/lib/_internal/libraries.dart'; |
26 | 26 |
27 import 'dart2yaml.dart'; | |
28 import 'io.dart'; | 27 import 'io.dart'; |
29 import 'library_helpers.dart'; | 28 import 'library_helpers.dart'; |
30 import 'models.dart'; | 29 import 'models.dart'; |
31 import 'package_helpers.dart' show packageNameFor, rootDirectory; | 30 import 'package_helpers.dart' show packageNameFor, rootDirectory; |
32 | 31 |
33 const String DEFAULT_OUTPUT_DIRECTORY = 'docs'; | 32 const String DEFAULT_OUTPUT_DIRECTORY = 'docs'; |
34 | 33 |
35 /// The directory where the output docs are generated. | 34 /// The directory where the output docs are generated. |
36 String get outputDirectory => _outputDirectory; | 35 String get outputDirectory => _outputDirectory; |
37 String _outputDirectory; | 36 String _outputDirectory; |
(...skipping 17 matching lines...) Expand all Loading... |
55 /// | 54 /// |
56 /// [packageRoot] is the packages directory of the directory being analyzed. | 55 /// [packageRoot] is the packages directory of the directory being analyzed. |
57 /// If [includeSdk] is `true`, then any SDK libraries explicitly imported will | 56 /// If [includeSdk] is `true`, then any SDK libraries explicitly imported will |
58 /// also be documented. | 57 /// also be documented. |
59 /// If [parseSdk] is `true`, then all Dart SDK libraries will be documented. | 58 /// If [parseSdk] is `true`, then all Dart SDK libraries will be documented. |
60 /// This option is useful when only the SDK libraries are needed. | 59 /// This option is useful when only the SDK libraries are needed. |
61 /// | 60 /// |
62 /// Returned Future completes with true if document generation is successful. | 61 /// Returned Future completes with true if document generation is successful. |
63 Future<bool> generateDocumentation(List<String> files, {String packageRoot, bool | 62 Future<bool> generateDocumentation(List<String> files, {String packageRoot, bool |
64 outputToYaml: true, bool includePrivate: false, bool includeSdk: false, bool | 63 outputToYaml: true, bool includePrivate: false, bool includeSdk: false, bool |
65 parseSdk: false, bool append: false, String introFileName: '', out: | 64 parseSdk: false, String introFileName: '', out: |
66 DEFAULT_OUTPUT_DIRECTORY, List<String> excludeLibraries: const [], bool | 65 DEFAULT_OUTPUT_DIRECTORY, List<String> excludeLibraries: const [], bool |
67 includeDependentPackages: false, String startPage, String dartBinary, String | 66 includeDependentPackages: false, String startPage, String dartBinary, String |
68 pubScript}) { | 67 pubScript}) { |
69 _excluded = excludeLibraries; | 68 _excluded = excludeLibraries; |
70 _pubScript = pubScript; | 69 _pubScript = pubScript; |
71 _dartBinary = dartBinary; | 70 _dartBinary = dartBinary; |
72 | 71 |
73 logger.onRecord.listen((record) => print(record.message)); | 72 logger.onRecord.listen((record) => print(record.message)); |
74 | 73 |
75 _ensureOutputDirectory(out, append); | 74 _ensureOutputDirectory(out); |
76 var updatedPackageRoot = _obtainPackageRoot(packageRoot, parseSdk, files); | 75 var updatedPackageRoot = _obtainPackageRoot(packageRoot, parseSdk, files); |
77 | 76 |
78 var requestedLibraries = _findLibrariesToDocument(files, | 77 var requestedLibraries = _findLibrariesToDocument(files, |
79 includeDependentPackages); | 78 includeDependentPackages); |
80 | 79 |
81 var allLibraries = []..addAll(requestedLibraries); | 80 var allLibraries = []..addAll(requestedLibraries); |
82 if (includeSdk) { | 81 if (includeSdk) { |
83 allLibraries.addAll(_listSdk()); | 82 allLibraries.addAll(_listSdk()); |
84 } | 83 } |
85 | 84 |
(...skipping 12 matching lines...) Expand all Loading... |
98 availableLibraries); | 97 availableLibraries); |
99 var librariesToDocument = requestedLibraries | 98 var librariesToDocument = requestedLibraries |
100 .map((each) { | 99 .map((each) { |
101 return availableLibrariesByPath | 100 return availableLibrariesByPath |
102 .putIfAbsent(each, () => throw "Missing library $each"); | 101 .putIfAbsent(each, () => throw "Missing library $each"); |
103 }).toList(); | 102 }).toList(); |
104 librariesToDocument.addAll((includeSdk || parseSdk) ? sdkLibraries : []); | 103 librariesToDocument.addAll((includeSdk || parseSdk) ? sdkLibraries : []); |
105 librariesToDocument.removeWhere((x) => _excluded.contains( | 104 librariesToDocument.removeWhere((x) => _excluded.contains( |
106 dart2js_util.nameOf(x))); | 105 dart2js_util.nameOf(x))); |
107 _documentLibraries(librariesToDocument, includeSdk: includeSdk, | 106 _documentLibraries(librariesToDocument, includeSdk: includeSdk, |
108 outputToYaml: outputToYaml, append: append, parseSdk: parseSdk, | 107 parseSdk: parseSdk, introFileName: introFileName, startPage: startPage); |
109 introFileName: introFileName, startPage: startPage); | |
110 return true; | 108 return true; |
111 }); | 109 }); |
112 } | 110 } |
113 | 111 |
114 | 112 |
115 /// Analyzes set of libraries by getting a mirror system and triggers the | 113 /// Analyzes set of libraries by getting a mirror system and triggers the |
116 /// documentation of the libraries. | 114 /// documentation of the libraries. |
117 Future<MirrorSystem> getMirrorSystem(List<Uri> libraries, | 115 Future<MirrorSystem> getMirrorSystem(List<Uri> libraries, |
118 bool includePrivate, {String packageRoot, bool parseSdk: false}) { | 116 bool includePrivate, {String packageRoot, bool parseSdk: false}) { |
119 if (libraries.isEmpty) throw new StateError('No Libraries.'); | 117 if (libraries.isEmpty) throw new StateError('No Libraries.'); |
120 | 118 |
121 includePrivateMembers = includePrivate; | 119 includePrivateMembers = includePrivate; |
122 | 120 |
123 // Finds the root of SDK library based off the location of docgen. | 121 // Finds the root of SDK library based off the location of docgen. |
124 // We have two different places to look, depending if we're in a development | 122 // We have two different places to look, depending if we're in a development |
125 // repo or in a built SDK, either sdk or dart-sdk respectively | 123 // repo or in a built SDK, either sdk or dart-sdk respectively |
126 var root = rootDirectory; | 124 var root = rootDirectory; |
127 var sdkRoot = path.normalize(path.absolute(path.join(root, 'sdk'))); | 125 var sdkRoot = path.normalize(path.absolute(path.join(root, 'sdk'))); |
128 if (!new Directory(sdkRoot).existsSync()) { | 126 if (!new Directory(sdkRoot).existsSync()) { |
129 sdkRoot = path.normalize(path.absolute(path.join(root, 'dart-sdk'))); | 127 sdkRoot = path.normalize(path.absolute(path.join(root, 'dart-sdk'))); |
130 } | 128 } |
131 logger.info('SDK Root: ${sdkRoot}'); | 129 logger.info('SDK Root: ${sdkRoot}'); |
132 return analyzeLibraries(libraries, sdkRoot, | 130 return analyzeLibraries(libraries, sdkRoot, |
133 packageRoot: packageRoot); | 131 packageRoot: packageRoot); |
134 } | 132 } |
135 | 133 |
136 /// Writes [text] to a file in the output directory. | 134 /// Writes [text] to a file in the output directory. |
137 void _writeToFile(String text, String filename, {bool append: false}) { | 135 void _writeToFile(String text, String filename) { |
138 if (text == null) return; | 136 if (text == null) return; |
139 Directory dir = new Directory(_outputDirectory); | 137 Directory dir = new Directory(_outputDirectory); |
140 if (!dir.existsSync()) { | 138 if (!dir.existsSync()) { |
141 dir.createSync(); | 139 dir.createSync(); |
142 } | 140 } |
143 if (path.split(filename).length > 1) { | 141 if (path.split(filename).length > 1) { |
144 var splitList = path.split(filename); | 142 var splitList = path.split(filename); |
145 for (int i = 0; i < splitList.length; i++) { | 143 for (int i = 0; i < splitList.length; i++) { |
146 var level = splitList[i]; | 144 var level = splitList[i]; |
147 } | 145 } |
148 for (var level in path.split(filename)) { | 146 for (var level in path.split(filename)) { |
149 var subdir = new Directory(path.join(_outputDirectory, path.dirname( | 147 var subdir = new Directory(path.join(_outputDirectory, path.dirname( |
150 filename))); | 148 filename))); |
151 if (!subdir.existsSync()) { | 149 if (!subdir.existsSync()) { |
152 subdir.createSync(); | 150 subdir.createSync(); |
153 } | 151 } |
154 } | 152 } |
155 } | 153 } |
156 File file = new File(path.join(_outputDirectory, filename)); | 154 File file = new File(path.join(_outputDirectory, filename)); |
157 file.writeAsStringSync(text, mode: append ? FileMode.APPEND : FileMode.WRITE); | 155 file.writeAsStringSync(text, mode: FileMode.WRITE); |
158 } | 156 } |
159 | 157 |
160 /// Resolve all the links in the introductory comments for a given library or | 158 /// Resolve all the links in the introductory comments for a given library or |
161 /// package as specified by [filename]. | 159 /// package as specified by [filename]. |
162 String _readIntroductionFile(String fileName, bool includeSdk) { | 160 String _readIntroductionFile(String fileName, bool includeSdk) { |
163 var linkResolver = (name) => globalFixReference(name); | 161 var linkResolver = (name) => globalFixReference(name); |
164 var defaultText = includeSdk ? _DEFAULT_SDK_INTRODUCTION : ''; | 162 var defaultText = includeSdk ? _DEFAULT_SDK_INTRODUCTION : ''; |
165 var introText = defaultText; | 163 var introText = defaultText; |
166 if (fileName.isNotEmpty) { | 164 if (fileName.isNotEmpty) { |
167 var introFile = new File(fileName); | 165 var introFile = new File(fileName); |
(...skipping 13 matching lines...) Expand all Loading... |
181 return compare; | 179 return compare; |
182 } | 180 } |
183 | 181 |
184 if (a is Library) return -1; | 182 if (a is Library) return -1; |
185 if (b is Library) return 1; | 183 if (b is Library) return 1; |
186 | 184 |
187 return a.qualifiedName.compareTo(b.qualifiedName); | 185 return a.qualifiedName.compareTo(b.qualifiedName); |
188 } | 186 } |
189 | 187 |
190 /// Creates documentation for filtered libraries. | 188 /// Creates documentation for filtered libraries. |
191 void _documentLibraries(List<LibraryMirror> libs, {bool includeSdk: false, bool | 189 void _documentLibraries(List<LibraryMirror> libs, {bool includeSdk: false, |
192 outputToYaml: true, bool append: false, bool parseSdk: false, String | 190 bool parseSdk: false, String introFileName: '', String startPage}) { |
193 introFileName: '', String startPage}) { | |
194 libs.forEach((lib) { | 191 libs.forEach((lib) { |
195 // Files belonging to the SDK have a uri that begins with 'dart:'. | 192 // Files belonging to the SDK have a uri that begins with 'dart:'. |
196 if (includeSdk || !lib.uri.toString().startsWith('dart:')) { | 193 if (includeSdk || !lib.uri.toString().startsWith('dart:')) { |
197 generateLibrary(lib); | 194 generateLibrary(lib); |
198 } | 195 } |
199 }); | 196 }); |
200 | 197 |
201 var filteredEntities = new SplayTreeSet<Indexable>(_indexableComparer); | 198 var filteredEntities = new SplayTreeSet<Indexable>(_indexableComparer); |
202 for (Map<String, Set<Indexable>> firstLevel in mirrorToDocgen.values) { | 199 for (Map<String, Set<Indexable>> firstLevel in mirrorToDocgen.values) { |
203 for (Set<Indexable> items in firstLevel.values) { | 200 for (Set<Indexable> items in firstLevel.values) { |
204 for (Indexable item in items) { | 201 for (Indexable item in items) { |
205 if (isFullChainVisible(item)) { | 202 if (isFullChainVisible(item)) { |
206 if (item is! Method || | 203 if (item is! Method || |
207 (item is Method && item.methodInheritedFrom == null)) { | 204 (item is Method && item.methodInheritedFrom == null)) { |
208 filteredEntities.add(item); | 205 filteredEntities.add(item); |
209 } | 206 } |
210 } | 207 } |
211 } | 208 } |
212 } | 209 } |
213 } | 210 } |
214 | 211 |
215 // Outputs a JSON file with all libraries and their preview comments. | 212 // Outputs a JSON file with all libraries and their preview comments. |
216 // This will help the viewer know what libraries are available to read in. | 213 // This will help the viewer know what libraries are available to read in. |
217 Map<String, dynamic> libraryMap; | 214 Map<String, dynamic> libraryMap = { |
218 | |
219 if (append) { | |
220 var docsDir = listDir(_outputDirectory); | |
221 if (!docsDir.contains('$_outputDirectory/library_list.json')) { | |
222 throw new StateError('No library_list.json'); | |
223 } | |
224 libraryMap = JSON.decode(new File('$_outputDirectory/library_list.json' | |
225 ).readAsStringSync()); | |
226 libraryMap['libraries'].addAll(filteredEntities.where((e) => e is Library | |
227 ).map((e) => e.previewMap)); | |
228 var intro = libraryMap['introduction']; | |
229 var spacing = intro.isEmpty ? '' : '<br/><br/>'; | |
230 libraryMap['introduction'] = | |
231 "$intro$spacing${_readIntroductionFile(introFileName, includeSdk)}"; | |
232 outputToYaml = libraryMap['filetype'] == 'yaml'; | |
233 } else { | |
234 libraryMap = { | |
235 'libraries': filteredEntities.where((e) => e is Library).map((e) => | 215 'libraries': filteredEntities.where((e) => e is Library).map((e) => |
236 e.previewMap).toList(), | 216 e.previewMap).toList(), |
237 'introduction': _readIntroductionFile(introFileName, includeSdk), | 217 'introduction': _readIntroductionFile(introFileName, includeSdk), |
238 'filetype': outputToYaml ? 'yaml' : 'json' | 218 'filetype': 'json' |
239 }; | 219 }; |
240 } | 220 _writeOutputFiles(libraryMap, filteredEntities, startPage); |
241 _writeOutputFiles(libraryMap, filteredEntities, outputToYaml, append, | |
242 startPage); | |
243 } | 221 } |
244 | 222 |
245 /// Output all of the libraries and classes into json or yaml files for | 223 /// Output all of the libraries and classes into json files for consumption by a |
246 /// consumption by a viewer. | 224 /// viewer. |
247 void _writeOutputFiles(Map<String, dynamic> libraryMap, Iterable<Indexable> | 225 void _writeOutputFiles(Map<String, dynamic> libraryMap, Iterable<Indexable> |
248 filteredEntities, bool outputToYaml, bool append, String startPage) { | 226 filteredEntities, String startPage) { |
249 if (startPage != null) libraryMap['start-page'] = startPage; | 227 if (startPage != null) libraryMap['start-page'] = startPage; |
250 | 228 |
251 _writeToFile(JSON.encode(libraryMap), 'library_list.json'); | 229 _writeToFile(JSON.encode(libraryMap), 'library_list.json'); |
252 | 230 |
253 // Output libraries and classes to file after all information is generated. | 231 // Output libraries and classes to file after all information is generated. |
254 filteredEntities.where((e) => e is Class || e is Library).forEach((output) { | 232 filteredEntities.where((e) => e is Class || e is Library).forEach((output) { |
255 _writeIndexableToFile(output, outputToYaml); | 233 _writeIndexableToFile(output); |
256 }); | 234 }); |
257 | 235 |
258 // Outputs all the qualified names documented with their type. | 236 // Outputs all the qualified names documented with their type. |
259 // This will help generate search results. | 237 // This will help generate search results. |
260 var sortedEntities = filteredEntities.map((e) => | 238 var sortedEntities = filteredEntities.map((e) => |
261 '${e.qualifiedName} ${e.typeName}').toList()..sort(); | 239 '${e.qualifiedName} ${e.typeName}').toList()..sort(); |
262 | 240 |
263 _writeToFile(sortedEntities.join('\n') + '\n', 'index.txt', append: append); | 241 _writeToFile(sortedEntities.join('\n') + '\n', 'index.txt'); |
264 var index = new SplayTreeMap.fromIterable(filteredEntities, | 242 var index = new SplayTreeMap.fromIterable(filteredEntities, |
265 key: (e) => e.qualifiedName, value: (e) => e.typeName); | 243 key: (e) => e.qualifiedName, value: (e) => e.typeName); |
266 | 244 |
267 if (append) { | |
268 var previousIndex = JSON.decode(new File('$_outputDirectory/index.json' | |
269 ).readAsStringSync()); | |
270 index.addAll(previousIndex); | |
271 } | |
272 _writeToFile(JSON.encode(index), 'index.json'); | 245 _writeToFile(JSON.encode(index), 'index.json'); |
273 } | 246 } |
274 | 247 |
275 /// Helper method to serialize the given Indexable out to a file. | 248 /// Helper method to serialize the given Indexable out to a file. |
276 void _writeIndexableToFile(Indexable result, bool outputToYaml) { | 249 void _writeIndexableToFile(Indexable result) { |
277 var outputFile = result.fileName; | 250 var outputFile = result.fileName + '.json'; |
278 var output; | 251 var output = JSON.encode(result.toMap()); |
279 if (outputToYaml) { | |
280 output = getYamlString(result.toMap()); | |
281 outputFile = outputFile + '.yaml'; | |
282 } else { | |
283 output = JSON.encode(result.toMap()); | |
284 outputFile = outputFile + '.json'; | |
285 } | |
286 _writeToFile(output, outputFile); | 252 _writeToFile(output, outputFile); |
287 } | 253 } |
288 | 254 |
289 /// Set the location of the ouput directory, and ensure that the location is | 255 /// Set the location of the ouput directory, and ensure that the location is |
290 /// available on the file system. | 256 /// available on the file system. |
291 void _ensureOutputDirectory(String outputDirectory, bool append) { | 257 void _ensureOutputDirectory(String outputDirectory) { |
292 _outputDirectory = outputDirectory; | 258 _outputDirectory = outputDirectory; |
293 if (!append) { | 259 var dir = new Directory(_outputDirectory); |
294 var dir = new Directory(_outputDirectory); | 260 if (dir.existsSync()) dir.deleteSync(recursive: true); |
295 if (dir.existsSync()) dir.deleteSync(recursive: true); | |
296 } | |
297 } | 261 } |
298 | 262 |
299 /// Analyzes set of libraries and provides a mirror system which can be used | 263 /// Analyzes set of libraries and provides a mirror system which can be used |
300 /// for static inspection of the source code. | 264 /// for static inspection of the source code. |
301 Future<MirrorSystem> analyzeLibraries(List<Uri> libraries, String | 265 Future<MirrorSystem> analyzeLibraries(List<Uri> libraries, String |
302 libraryRoot, {String packageRoot}) { | 266 libraryRoot, {String packageRoot}) { |
303 SourceFileProvider provider = new CompilerSourceFileProvider(); | 267 SourceFileProvider provider = new CompilerSourceFileProvider(); |
304 api.DiagnosticHandler diagnosticHandler = (new FormattingDiagnosticHandler( | 268 api.DiagnosticHandler diagnosticHandler = (new FormattingDiagnosticHandler( |
305 provider) | 269 provider) |
306 ..showHints = false | 270 ..showHints = false |
(...skipping 12 matching lines...) Expand all Loading... |
319 // system, and it is not possible to use the stack trace. BUG(#11622) | 283 // system, and it is not possible to use the stack trace. BUG(#11622) |
320 // To avoid printing the stack trace. | 284 // To avoid printing the stack trace. |
321 exit(1); | 285 exit(1); |
322 }); | 286 }); |
323 } | 287 } |
324 | 288 |
325 /// For this run of docgen, determine the packageRoot value. | 289 /// For this run of docgen, determine the packageRoot value. |
326 /// | 290 /// |
327 /// If packageRoot is not explicitly passed, we examine the files we're | 291 /// If packageRoot is not explicitly passed, we examine the files we're |
328 /// documenting to attempt to find a package root. | 292 /// documenting to attempt to find a package root. |
329 String _obtainPackageRoot(String packageRoot, bool parseSdk, List<String> files) | 293 String _obtainPackageRoot(String packageRoot, bool parseSdk, |
330 { | 294 List<String> files) { |
331 if (packageRoot == null && !parseSdk) { | 295 if (packageRoot == null && !parseSdk) { |
332 var type = FileSystemEntity.typeSync(files.first); | 296 var type = FileSystemEntity.typeSync(files.first); |
333 if (type == FileSystemEntityType.DIRECTORY) { | 297 if (type == FileSystemEntityType.DIRECTORY) { |
334 var files2 = listDir(files.first, recursive: true); | 298 var files2 = listDir(files.first, recursive: true); |
335 // Return '' means that there was no pubspec.yaml and therefor no p | 299 // Return '' means that there was no pubspec.yaml and therefor no p |
336 // ackageRoot. | 300 // ackageRoot. |
337 packageRoot = files2.firstWhere((f) => f.endsWith( | 301 packageRoot = files2.firstWhere((f) => f.endsWith( |
338 '${path.separator}pubspec.yaml'), orElse: () => ''); | 302 '${path.separator}pubspec.yaml'), orElse: () => ''); |
339 if (packageRoot != '') { | 303 if (packageRoot != '') { |
340 packageRoot = path.join(path.dirname(packageRoot), 'packages'); | 304 packageRoot = path.join(path.dirname(packageRoot), 'packages'); |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
499 * [Samples](http://www.dartlang.org/samples/) | 463 * [Samples](http://www.dartlang.org/samples/) |
500 * [A Tour of the Dart Libraries](http://www.dartlang.org/docs/dart-up-and-runn
ing/contents/ch03.html) | 464 * [A Tour of the Dart Libraries](http://www.dartlang.org/docs/dart-up-and-runn
ing/contents/ch03.html) |
501 | 465 |
502 This API reference is automatically generated from the source code in the | 466 This API reference is automatically generated from the source code in the |
503 [Dart project](https://code.google.com/p/dart/). | 467 [Dart project](https://code.google.com/p/dart/). |
504 If you'd like to contribute to this documentation, see | 468 If you'd like to contribute to this documentation, see |
505 [Contributing](https://code.google.com/p/dart/wiki/Contributing) | 469 [Contributing](https://code.google.com/p/dart/wiki/Contributing) |
506 and | 470 and |
507 [Writing API Documentation](https://code.google.com/p/dart/wiki/WritingApiDocume
ntation). | 471 [Writing API Documentation](https://code.google.com/p/dart/wiki/WritingApiDocume
ntation). |
508 """; | 472 """; |
OLD | NEW |