| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 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 | 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 /// **docgen** is a tool for creating machine readable representations of Dart | 5 /// **docgen** is a tool for creating machine readable representations of Dart |
| 6 /// code metadata, including: classes, members, comments and annotations. | 6 /// code metadata, including: classes, members, comments and annotations. |
| 7 /// | 7 /// |
| 8 /// docgen is run on a `.dart` file or a directory containing `.dart` files. | 8 /// docgen is run on a `.dart` file or a directory containing `.dart` files. |
| 9 /// | 9 /// |
| 10 /// $ dart docgen.dart [OPTIONS] [FILE/DIR] | 10 /// $ dart docgen.dart [OPTIONS] [FILE/DIR] |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirro
r.dart' | 29 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirro
r.dart' |
| 30 as dart2js; | 30 as dart2js; |
| 31 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart'
; | 31 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart'
; |
| 32 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.
dart' | 32 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.
dart' |
| 33 as dart2js_util; | 33 as dart2js_util; |
| 34 import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider.
dart'; | 34 import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider.
dart'; |
| 35 import '../../../sdk/lib/_internal/libraries.dart'; | 35 import '../../../sdk/lib/_internal/libraries.dart'; |
| 36 | 36 |
| 37 var logger = new Logger('Docgen'); | 37 var logger = new Logger('Docgen'); |
| 38 | 38 |
| 39 const DEFAULT_OUTPUT_DIRECTORY = 'docs'; |
| 40 |
| 41 var _outputDirectory; |
| 42 |
| 39 const String USAGE = 'Usage: dart docgen.dart [OPTIONS] fooDir/barFile'; | 43 const String USAGE = 'Usage: dart docgen.dart [OPTIONS] fooDir/barFile'; |
| 40 | 44 |
| 41 | 45 |
| 42 List<String> skippedAnnotations = const [ | 46 List<String> skippedAnnotations = const [ |
| 43 'metadata.DocsEditable', '_js_helper.JSName', '_js_helper.Creates', | 47 'metadata.DocsEditable', '_js_helper.JSName', '_js_helper.Creates', |
| 44 '_js_helper.Returns']; | 48 '_js_helper.Returns']; |
| 45 | 49 |
| 46 /// Set of libraries declared in the SDK, so libraries that can be accessed | 50 /// Set of libraries declared in the SDK, so libraries that can be accessed |
| 47 /// when running dart by default. | 51 /// when running dart by default. |
| 48 Iterable<LibraryMirror> _sdkLibraries; | 52 Iterable<LibraryMirror> _sdkLibraries; |
| 49 | 53 |
| 50 /// The dart:core library, which contains all types that are always available | 54 /// The dart:core library, which contains all types that are always available |
| 51 /// without import. | 55 /// without import. |
| 52 LibraryMirror _coreLibrary; | 56 LibraryMirror _coreLibrary; |
| 53 | 57 |
| 54 /// Support for [:foo:]-style code comments to the markdown parser. | 58 /// Support for [:foo:]-style code comments to the markdown parser. |
| 55 List<markdown.InlineSyntax> markdownSyntaxes = | 59 List<markdown.InlineSyntax> markdownSyntaxes = |
| 56 [new markdown.CodeSyntax(r'\[:\s?((?:.|\n)*?)\s?:\]')]; | 60 [new markdown.CodeSyntax(r'\[:\s?((?:.|\n)*?)\s?:\]')]; |
| 57 | 61 |
| 58 /// Index of all indexable items. This also ensures that no class is | 62 /// Index of all indexable items. This also ensures that no class is |
| 59 /// created more than once. | 63 /// created more than once. |
| 60 Map<String, Indexable> entityMap = new Map<String, Indexable>(); | 64 Map<String, Indexable> entityMap = new Map<String, Indexable>(); |
| 61 | 65 |
| 62 /// This is set from the command line arguments flag --include-private | 66 /// This is set from the command line arguments flag --include-private |
| 63 bool _includePrivate = false; | 67 bool _includePrivate = false; |
| 64 | 68 |
| 69 /// Library names to explicitly exclude. |
| 70 /// |
| 71 /// Set from the command line option |
| 72 /// --exclude-lib. |
| 73 List<String> _excluded; |
| 74 |
| 65 // TODO(janicejl): Make MDN content generic or pluggable. Maybe move | 75 // TODO(janicejl): Make MDN content generic or pluggable. Maybe move |
| 66 // MDN-specific code to its own library that is imported into the default impl? | 76 // MDN-specific code to its own library that is imported into the default impl? |
| 67 /// Map of all the comments for dom elements from MDN. | 77 /// Map of all the comments for dom elements from MDN. |
| 68 Map _mdn; | 78 Map _mdn; |
| 69 | 79 |
| 70 /// Docgen constructor initializes the link resolver for markdown parsing. | 80 /// Docgen constructor initializes the link resolver for markdown parsing. |
| 71 /// Also initializes the command line arguments. | 81 /// Also initializes the command line arguments. |
| 72 /// | 82 /// |
| 73 /// [packageRoot] is the packages directory of the directory being analyzed. | 83 /// [packageRoot] is the packages directory of the directory being analyzed. |
| 74 /// If [includeSdk] is `true`, then any SDK libraries explicitly imported will | 84 /// If [includeSdk] is `true`, then any SDK libraries explicitly imported will |
| 75 /// also be documented. | 85 /// also be documented. |
| 76 /// If [parseSdk] is `true`, then all Dart SDK libraries will be documented. | 86 /// If [parseSdk] is `true`, then all Dart SDK libraries will be documented. |
| 77 /// This option is useful when only the SDK libraries are needed. | 87 /// This option is useful when only the SDK libraries are needed. |
| 78 /// | 88 /// |
| 79 /// Returned Future completes with true if document generation is successful. | 89 /// Returned Future completes with true if document generation is successful. |
| 80 Future<bool> docgen(List<String> files, {String packageRoot, | 90 Future<bool> docgen(List<String> files, {String packageRoot, |
| 81 bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false, | 91 bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false, |
| 82 bool parseSdk: false, bool append: false, String introduction: ''}) { | 92 bool parseSdk: false, bool append: false, String introduction: '', |
| 93 out: DEFAULT_OUTPUT_DIRECTORY, List<String> excludeLibraries}) { |
| 94 _excluded = excludeLibraries; |
| 83 _includePrivate = includePrivate; | 95 _includePrivate = includePrivate; |
| 96 _outputDirectory = out; |
| 84 if (!append) { | 97 if (!append) { |
| 85 var dir = new Directory('docs'); | 98 var dir = new Directory(_outputDirectory); |
| 86 if (dir.existsSync()) dir.deleteSync(recursive: true); | 99 if (dir.existsSync()) dir.deleteSync(recursive: true); |
| 87 } | 100 } |
| 88 | 101 |
| 89 if (packageRoot == null && !parseSdk) { | 102 if (packageRoot == null && !parseSdk) { |
| 90 var type = FileSystemEntity.typeSync(files.first); | 103 var type = FileSystemEntity.typeSync(files.first); |
| 91 if (type == FileSystemEntityType.DIRECTORY) { | 104 if (type == FileSystemEntityType.DIRECTORY) { |
| 92 packageRoot = _findPackageRoot(files.first); | 105 packageRoot = _findPackageRoot(files.first); |
| 93 } else if (type == FileSystemEntityType.FILE) { | 106 } else if (type == FileSystemEntityType.FILE) { |
| 94 logger.warning('WARNING: No package root defined. If Docgen fails, try ' | 107 logger.warning('WARNING: No package root defined. If Docgen fails, try ' |
| 95 'again by setting the --package-root option.'); | 108 'again by setting the --package-root option.'); |
| 96 } | 109 } |
| 97 } | 110 } |
| 98 logger.info('Package Root: ${packageRoot}'); | 111 logger.info('Package Root: ${packageRoot}'); |
| 112 var requestedLibraries = _listLibraries(files); |
| 113 var allLibraries = []..addAll(requestedLibraries); |
| 114 if (includeSdk) { |
| 115 allLibraries.addAll(_listSdk()); |
| 116 } |
| 99 | 117 |
| 100 return getMirrorSystem(files, packageRoot: packageRoot, parseSdk: parseSdk) | 118 return getMirrorSystem(allLibraries, packageRoot: packageRoot, |
| 119 parseSdk: parseSdk) |
| 101 .then((MirrorSystem mirrorSystem) { | 120 .then((MirrorSystem mirrorSystem) { |
| 102 if (mirrorSystem.libraries.isEmpty) { | 121 if (mirrorSystem.libraries.isEmpty) { |
| 103 throw new StateError('No library mirrors were created.'); | 122 throw new StateError('No library mirrors were created.'); |
| 104 } | 123 } |
| 105 var librariesWeAskedFor = _listLibraries(files); | 124 var availableLibraries = mirrorSystem.libraries.values.where( |
| 106 var librariesWeGot = mirrorSystem.libraries.values.where( | |
| 107 (each) => each.uri.scheme == 'file'); | 125 (each) => each.uri.scheme == 'file'); |
| 108 _sdkLibraries = mirrorSystem.libraries.values.where( | 126 _sdkLibraries = mirrorSystem.libraries.values.where( |
| 109 (each) => each.uri.scheme == 'dart'); | 127 (each) => each.uri.scheme == 'dart'); |
| 110 _coreLibrary = _sdkLibraries.singleWhere((lib) => | 128 _coreLibrary = _sdkLibraries.singleWhere((lib) => |
| 111 lib.uri.toString().startsWith('dart:core')); | 129 lib.uri.toString().startsWith('dart:core')); |
| 112 var librariesWeGotByPath = new Map.fromIterables( | 130 var availableLibrariesByPath = new Map.fromIterables( |
| 113 librariesWeGot.map((each) => each.uri.toFilePath()), | 131 availableLibraries.map((each) => each.uri.toFilePath()), |
| 114 librariesWeGot); | 132 availableLibraries); |
| 115 var librariesToDocument = librariesWeAskedFor.map( | 133 var librariesToDocument = requestedLibraries.map( |
| 116 (each) => librariesWeGotByPath.putIfAbsent(each, | 134 (each) => availableLibrariesByPath.putIfAbsent(each, |
| 117 () => throw "Missing library $each")).toList(); | 135 () => throw "Missing library $each")).toList(); |
| 118 librariesToDocument.addAll((includeSdk || parseSdk) ? _sdkLibraries : []); | 136 librariesToDocument.addAll((includeSdk || parseSdk) ? _sdkLibraries : []); |
| 137 librariesToDocument.removeWhere((x) => _excluded.contains(x.simpleName)); |
| 119 _documentLibraries(librariesToDocument, includeSdk: includeSdk, | 138 _documentLibraries(librariesToDocument, includeSdk: includeSdk, |
| 120 outputToYaml: outputToYaml, append: append, parseSdk: parseSdk, | 139 outputToYaml: outputToYaml, append: append, parseSdk: parseSdk, |
| 121 introduction: introduction); | 140 introduction: introduction); |
| 122 return true; | 141 return true; |
| 123 }); | 142 }); |
| 124 } | 143 } |
| 125 | 144 |
| 126 /// For a library's [mirror], determine the name of the package (if any) we | 145 /// For a library's [mirror], determine the name of the package (if any) we |
| 127 /// believe it came from (because of its file URI). | 146 /// believe it came from (because of its file URI). |
| 128 /// | 147 /// |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 // Only add the file if it does not contain 'part of' | 221 // Only add the file if it does not contain 'part of' |
| 203 // TODO(janicejl): Remove when Issue(12406) is resolved. | 222 // TODO(janicejl): Remove when Issue(12406) is resolved. |
| 204 var contents = new File(f).readAsStringSync(); | 223 var contents = new File(f).readAsStringSync(); |
| 205 if (!(contents.contains(new RegExp('\npart of ')) || | 224 if (!(contents.contains(new RegExp('\npart of ')) || |
| 206 contents.startsWith(new RegExp('part of ')))) { | 225 contents.startsWith(new RegExp('part of ')))) { |
| 207 libraries.add(f); | 226 libraries.add(f); |
| 208 logger.info('Added to libraries: $f'); | 227 logger.info('Added to libraries: $f'); |
| 209 } | 228 } |
| 210 } | 229 } |
| 211 }); | 230 }); |
| 212 return libraries; | 231 return libraries.map(path.absolute).map(path.normalize).toList(); |
| 213 } | 232 } |
| 214 | 233 |
| 215 String _findPackageRoot(String directory) { | 234 String _findPackageRoot(String directory) { |
| 216 var files = listDir(directory, recursive: true); | 235 var files = listDir(directory, recursive: true); |
| 217 // Return '' means that there was no pubspec.yaml and therefor no packageRoot. | 236 // Return '' means that there was no pubspec.yaml and therefor no packageRoot. |
| 218 String packageRoot = files.firstWhere((f) => | 237 String packageRoot = files.firstWhere((f) => |
| 219 f.endsWith('${path.separator}pubspec.yaml'), orElse: () => ''); | 238 f.endsWith('${path.separator}pubspec.yaml'), orElse: () => ''); |
| 220 if (packageRoot != '') { | 239 if (packageRoot != '') { |
| 221 packageRoot = path.join(path.dirname(packageRoot), 'packages'); | 240 packageRoot = path.join(path.dirname(packageRoot), 'packages'); |
| 222 } | 241 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 238 if (info.documented) { | 257 if (info.documented) { |
| 239 sdk.add('dart:$name'); | 258 sdk.add('dart:$name'); |
| 240 logger.info('Add to SDK: ${sdk.last}'); | 259 logger.info('Add to SDK: ${sdk.last}'); |
| 241 } | 260 } |
| 242 }); | 261 }); |
| 243 return sdk; | 262 return sdk; |
| 244 } | 263 } |
| 245 | 264 |
| 246 /// Analyzes set of libraries by getting a mirror system and triggers the | 265 /// Analyzes set of libraries by getting a mirror system and triggers the |
| 247 /// documentation of the libraries. | 266 /// documentation of the libraries. |
| 248 Future<MirrorSystem> getMirrorSystem(List<String> args, {String packageRoot, | 267 Future<MirrorSystem> getMirrorSystem(List<String> libraries, |
| 249 bool parseSdk: false}) { | 268 {String packageRoot, bool parseSdk: false}) { |
| 250 var libraries = !parseSdk ? _listLibraries(args) : _listSdk(); | |
| 251 if (libraries.isEmpty) throw new StateError('No Libraries.'); | 269 if (libraries.isEmpty) throw new StateError('No Libraries.'); |
| 252 // Finds the root of SDK library based off the location of docgen. | 270 // Finds the root of SDK library based off the location of docgen. |
| 253 | 271 |
| 254 var root = findRootDirectory(); | 272 var root = findRootDirectory(); |
| 255 var sdkRoot = path.normalize(path.absolute(path.join(root, 'sdk'))); | 273 var sdkRoot = path.normalize(path.absolute(path.join(root, 'sdk'))); |
| 256 logger.info('SDK Root: ${sdkRoot}'); | 274 logger.info('SDK Root: ${sdkRoot}'); |
| 257 return _analyzeLibraries(libraries, sdkRoot, packageRoot: packageRoot); | 275 return _analyzeLibraries(libraries, sdkRoot, packageRoot: packageRoot); |
| 258 } | 276 } |
| 259 | 277 |
| 260 String findRootDirectory() { | 278 String findRootDirectory() { |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 316 // giant list of subclasses to be printed out. | 334 // giant list of subclasses to be printed out. |
| 317 if (includeSdk) (entityMap['dart-core.Object'] as Class).subclasses.clear(); | 335 if (includeSdk) (entityMap['dart-core.Object'] as Class).subclasses.clear(); |
| 318 | 336 |
| 319 var filteredEntities = entityMap.values.where(_isVisible); | 337 var filteredEntities = entityMap.values.where(_isVisible); |
| 320 | 338 |
| 321 // Outputs a JSON file with all libraries and their preview comments. | 339 // Outputs a JSON file with all libraries and their preview comments. |
| 322 // This will help the viewer know what libraries are available to read in. | 340 // This will help the viewer know what libraries are available to read in. |
| 323 var libraryMap; | 341 var libraryMap; |
| 324 var linkResolver = (name) => fixReference(name, null, null, null); | 342 var linkResolver = (name) => fixReference(name, null, null, null); |
| 325 if (append) { | 343 if (append) { |
| 326 var docsDir = listDir('docs'); | 344 var docsDir = listDir(_outputDirectory); |
| 327 if (!docsDir.contains('docs/library_list.json')) { | 345 if (!docsDir.contains('$_outputDirectory/library_list.json')) { |
| 328 throw new StateError('No library_list.json'); | 346 throw new StateError('No library_list.json'); |
| 329 } | 347 } |
| 330 libraryMap = | 348 libraryMap = |
| 331 JSON.decode(new File('docs/library_list.json').readAsStringSync()); | 349 JSON.decode(new File('$_outputDirectory/library_list.json').readAsString
Sync()); |
| 332 libraryMap['libraries'].addAll(filteredEntities | 350 libraryMap['libraries'].addAll(filteredEntities |
| 333 .where((e) => e is Library) | 351 .where((e) => e is Library) |
| 334 .map((e) => e.previewMap)); | 352 .map((e) => e.previewMap)); |
| 335 if (introduction.isNotEmpty) { | 353 if (introduction.isNotEmpty) { |
| 336 var intro = libraryMap['introduction']; | 354 var intro = libraryMap['introduction']; |
| 337 if (intro.isNotEmpty) intro += '<br/><br/>'; | 355 if (intro.isNotEmpty) intro += '<br/><br/>'; |
| 338 intro += markdown.markdownToHtml( | 356 intro += markdown.markdownToHtml( |
| 339 new File(introduction).readAsStringSync(), | 357 new File(introduction).readAsStringSync(), |
| 340 linkResolver: linkResolver, inlineSyntaxes: markdownSyntaxes); | 358 linkResolver: linkResolver, inlineSyntaxes: markdownSyntaxes); |
| 341 libraryMap['introduction'] = intro; | 359 libraryMap['introduction'] = intro; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 362 // Outputs all the qualified names documented with their type. | 380 // Outputs all the qualified names documented with their type. |
| 363 // This will help generate search results. | 381 // This will help generate search results. |
| 364 _writeToFile(filteredEntities.map((e) => | 382 _writeToFile(filteredEntities.map((e) => |
| 365 '${e.qualifiedName} ${e.typeName}').join('\n') + '\n', | 383 '${e.qualifiedName} ${e.typeName}').join('\n') + '\n', |
| 366 'index.txt', append: append); | 384 'index.txt', append: append); |
| 367 var index = new Map.fromIterables( | 385 var index = new Map.fromIterables( |
| 368 filteredEntities.map((e) => e.qualifiedName), | 386 filteredEntities.map((e) => e.qualifiedName), |
| 369 filteredEntities.map((e) => e.typeName)); | 387 filteredEntities.map((e) => e.typeName)); |
| 370 if (append) { | 388 if (append) { |
| 371 var previousIndex = | 389 var previousIndex = |
| 372 JSON.decode(new File('docs/index.json').readAsStringSync()); | 390 JSON.decode(new File('$_outputDirectory/index.json').readAsStringSync())
; |
| 373 index.addAll(previousIndex); | 391 index.addAll(previousIndex); |
| 374 } | 392 } |
| 375 _writeToFile(JSON.encode(index), 'index.json'); | 393 _writeToFile(JSON.encode(index), 'index.json'); |
| 376 } | 394 } |
| 377 | 395 |
| 378 Library generateLibrary(dart2js.Dart2JsLibraryMirror library) { | 396 Library generateLibrary(dart2js.Dart2JsLibraryMirror library) { |
| 379 var result = new Library(docName(library), | 397 var result = new Library(docName(library), |
| 380 (actualLibrary) => _commentToHtml(library, actualLibrary), | 398 (actualLibrary) => _commentToHtml(library, actualLibrary), |
| 381 _classes(library.classes), | 399 _classes(library.classes), |
| 382 _methods(library.functions), | 400 _methods(library.functions), |
| (...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 764 if (mirror is ClassMirror && !mirror.isTypedef) { | 782 if (mirror is ClassMirror && !mirror.isTypedef) { |
| 765 var innerList = []; | 783 var innerList = []; |
| 766 mirror.typeArguments.forEach((e) { | 784 mirror.typeArguments.forEach((e) { |
| 767 innerList.add(new Type(docName(e), _typeGenerics(e))); | 785 innerList.add(new Type(docName(e), _typeGenerics(e))); |
| 768 }); | 786 }); |
| 769 return innerList; | 787 return innerList; |
| 770 } | 788 } |
| 771 return []; | 789 return []; |
| 772 } | 790 } |
| 773 | 791 |
| 774 /// Writes text to a file in the 'docs' directory. | 792 /// Writes text to a file in the output directory. |
| 775 void _writeToFile(String text, String filename, {bool append: false}) { | 793 void _writeToFile(String text, String filename, {bool append: false}) { |
| 776 Directory dir = new Directory('docs'); | 794 if (text == null) return; |
| 795 Directory dir = new Directory(_outputDirectory); |
| 777 if (!dir.existsSync()) { | 796 if (!dir.existsSync()) { |
| 778 dir.createSync(); | 797 dir.createSync(); |
| 779 } | 798 } |
| 780 // We assume there's a single extra level of directory structure for packages. | 799 // We assume there's a single extra level of directory structure for packages. |
| 781 if (path.split(filename).length > 1) { | 800 if (path.split(filename).length > 1) { |
| 782 var subdir = new Directory(path.join('docs', path.dirname(filename))); | 801 var subdir = new Directory(path.join(_outputDirectory, path.dirname(filename
))); |
| 783 if (!subdir.existsSync()) { | 802 if (!subdir.existsSync()) { |
| 784 subdir.createSync(); | 803 subdir.createSync(); |
| 785 } | 804 } |
| 786 } | 805 } |
| 787 | 806 File file = new File(path.join(_outputDirectory, filename)); |
| 788 File file = new File('docs/$filename'); | |
| 789 if (!file.existsSync()) { | |
| 790 file.createSync(); | |
| 791 } | |
| 792 file.writeAsStringSync(text, mode: append ? FileMode.APPEND : FileMode.WRITE); | 807 file.writeAsStringSync(text, mode: append ? FileMode.APPEND : FileMode.WRITE); |
| 793 } | 808 } |
| 794 | 809 |
| 795 /// Transforms the map by calling toMap on each value in it. | 810 /// Transforms the map by calling toMap on each value in it. |
| 796 Map recurseMap(Map inputMap) { | 811 Map recurseMap(Map inputMap) { |
| 797 var outputMap = {}; | 812 var outputMap = {}; |
| 798 inputMap.forEach((key, value) { | 813 inputMap.forEach((key, value) { |
| 799 if (value is Map) { | 814 if (value is Map) { |
| 800 outputMap[key] = recurseMap(value); | 815 outputMap[key] = recurseMap(value); |
| 801 } else { | 816 } else { |
| (...skipping 632 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1434 /// Remove statics from the map of inherited items before adding them. | 1449 /// Remove statics from the map of inherited items before adding them. |
| 1435 Map _filterStatics(Map items) { | 1450 Map _filterStatics(Map items) { |
| 1436 var result = {}; | 1451 var result = {}; |
| 1437 items.forEach((name, item) { | 1452 items.forEach((name, item) { |
| 1438 if (!item.isStatic) { | 1453 if (!item.isStatic) { |
| 1439 result[name] = item; | 1454 result[name] = item; |
| 1440 } | 1455 } |
| 1441 }); | 1456 }); |
| 1442 return result; | 1457 return result; |
| 1443 } | 1458 } |
| OLD | NEW |