Chromium Code Reviews| Index: modules/angular2/src/transform/traversal.dart |
| diff --git a/modules/angular2/src/transform/traversal.dart b/modules/angular2/src/transform/traversal.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..f727b1677005a748698365cbe0b9dee7d958534f |
| --- /dev/null |
| +++ b/modules/angular2/src/transform/traversal.dart |
| @@ -0,0 +1,100 @@ |
| +import 'package:analyzer/src/generated/element.dart'; |
| +import 'package:path/path.dart' as path; |
| + |
| +import 'annotation_processor.dart'; |
| + |
| +class ImportTraversal { |
|
jakemac
2015/02/17 23:46:46
ImportTraverser maybe?
tjblasi
2015/02/18 21:18:25
Acknowledged.
|
| + final AnnotationMatcher _annotationMatcher; |
| + |
| + ImportTraversal(this._annotationMatcher); |
| + |
| + /// Reads Initializer annotations on this library and all its dependencies in |
| + /// post-order. |
| + void traverse(LibraryElement library, [Set<LibraryElement> seen]) { |
|
jakemac
2015/02/18 16:18:50
Looks to me like this is still doing the normal tr
tjblasi
2015/02/18 21:18:25
Discussed offline
|
| + if (seen == null) seen = new Set<LibraryElement>(); |
| + seen.add(library); |
| + |
| + // Visit all our dependencies. |
| + for (var importedLibrary in _sortedLibraryImports(library)) { |
| + // Don't include anything from the sdk. |
| + if (importedLibrary.isInSdk) continue; |
| + if (seen.contains(importedLibrary)) continue; |
| + traverse(importedLibrary, seen); |
| + } |
| + |
| + for (var clazz in _classesOfLibrary(library, seen)) { |
| + var superClass = clazz.supertype; |
| + while (superClass != null) { |
| + if (_annotationMatcher.processAnnotations(superClass.element) && |
|
jakemac
2015/02/17 23:46:46
I think that for angular this might not matter, as
tjblasi
2015/02/18 21:18:25
Acknowledged.
|
| + superClass.element.library != clazz.library) { |
| + _logger.warning( |
| + 'We have detected a cycle in your import graph when running ' |
| + 'initializers on ${clazz.name}. This means the super class ' |
| + '${superClass.name} has a dependency on this library ' |
| + '(possibly transitive).'); |
| + } |
| + superClass = superClass.superclass; |
| + } |
| + _annotationMatcher.processAnnotations(clazz); |
| + } |
| + } |
| + |
| + /// Retrieves all classes that are visible if you were to import [lib]. This |
| + /// includes exported classes from other libraries. |
| + List<ClassElement> _classesOfLibrary( |
| + LibraryElement library, Set<LibraryElement> seen) { |
| + var result = []; |
| + result.addAll(library.units.expand((u) => u.types)); |
| + for (var export in library.exports) { |
| + if (seen.contains(export.exportedLibrary)) continue; |
| + var exported = _classesOfLibrary(export.exportedLibrary, seen); |
| + _filter(exported, export.combinators); |
| + result.addAll(exported); |
| + } |
| + result.sort((a, b) => a.name.compareTo(b.name)); |
| + return result; |
| + } |
| + |
| + /// Filters [elements] that come from an export, according to its show/hide |
| + /// combinators. This modifies [elements] in place. |
| + void _filter(List<Element> elements, List<NamespaceCombinator> combinators) { |
| + for (var c in combinators) { |
| + if (c is ShowElementCombinator) { |
| + var show = c.shownNames.toSet(); |
| + elements.retainWhere((e) => show.contains(e.displayName)); |
| + } else if (c is HideElementCombinator) { |
| + var hide = c.hiddenNames.toSet(); |
| + elements.removeWhere((e) => hide.contains(e.displayName)); |
| + } |
| + } |
| + } |
| + |
| + Iterable<LibraryElement> _sortedLibraryImports(LibraryElement library) => |
| + (new List.from(library.imports) |
| + ..sort((ImportElement a, ImportElement b) { |
| + // dart: imports don't have a uri |
| + if (a.uri == null && b.uri != null) return -1; |
| + if (b.uri == null && a.uri != null) return 1; |
| + if (a.uri == null && b.uri == null) { |
| + return a.importedLibrary.name.compareTo(b.importedLibrary.name); |
| + } |
| + |
| + // package: imports next |
| + var aIsPackage = a.uri.startsWith('package:'); |
| + var bIsPackage = b.uri.startsWith('package:'); |
| + if (aIsPackage && !bIsPackage) { |
| + return -1; |
| + } else if (bIsPackage && !aIsPackage) { |
| + return 1; |
| + } else if (bIsPackage && aIsPackage) { |
| + return a.uri.compareTo(b.uri); |
| + } |
| + |
| + // And finally compare based on the relative uri if both are file paths. |
| + var aUri = path.relative(a.source.uri.path, |
| + from: path.dirname(library.source.uri.path)); |
| + var bUri = path.relative(b.source.uri.path, |
| + from: path.dirname(library.source.uri.path)); |
| + return aUri.compareTo(bUri); |
| + })).map((import) => import.importedLibrary); |
| +} |