refactor(dart/transform): Correct Dart analyzer warnings
- Fix numerous Dart analyzer warnings we had been ignoring. - Delete unused `in_progress` dir
This commit is contained in:
parent
aba61f22a6
commit
7cac7c5157
|
@ -14,6 +14,7 @@ dependencies:
|
|||
code_transformers: '^0.2.5'
|
||||
dart_style: '^0.1.3'
|
||||
html: '^0.12.0'
|
||||
source_span: '^1.0.0'
|
||||
stack_trace: '^1.1.1'
|
||||
transformers:
|
||||
- angular2
|
||||
|
|
|
@ -16,6 +16,36 @@ class Html5LibDomAdapter implements DomAdapter {
|
|||
'tabindex': 'tabIndex',
|
||||
};
|
||||
|
||||
@override
|
||||
getGlobalEventTarget(String target) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
@override
|
||||
getTitle() {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
@override
|
||||
setTitle(String newTitle) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
@override
|
||||
String getEventKey(event) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
@override
|
||||
void replaceChild(el, newNode, oldNode) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic getBoundingClientRect(el) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
Element parse(String templateHtml) => parser.parse(templateHtml).firstChild;
|
||||
query(selector) {
|
||||
throw 'not implemented';
|
||||
|
@ -54,7 +84,7 @@ class Html5LibDomAdapter implements DomAdapter {
|
|||
String type(node) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
content(TemplateElement node) {
|
||||
content(node) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
library angular2.transform.common.logging;
|
||||
|
||||
import 'dart:async';
|
||||
import 'package:barback/barback.dart';
|
||||
import 'package:code_transformers/messages/build_logger.dart';
|
||||
import 'package:source_span/source_span.dart';
|
||||
|
||||
BuildLogger _logger;
|
||||
|
||||
|
@ -24,6 +26,11 @@ BuildLogger get logger {
|
|||
}
|
||||
|
||||
class PrintLogger implements BuildLogger {
|
||||
@override
|
||||
final String detailsUri = '';
|
||||
@override
|
||||
final bool convertErrorsToWarnings = false;
|
||||
|
||||
void _printWithPrefix(prefix, msg) => print('$prefix: $msg');
|
||||
void info(msg, {AssetId asset, SourceSpan span}) =>
|
||||
_printWithPrefix('INFO', msg);
|
||||
|
@ -43,7 +50,7 @@ class PrintLoggerError extends Error {
|
|||
final AssetId asset;
|
||||
final SourceSpan span;
|
||||
|
||||
PrintLoggerError(message, asset, span);
|
||||
PrintLoggerError(this.message, this.asset, this.span);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
|
|
|
@ -3,6 +3,7 @@ library angular2.transform.common.names;
|
|||
const SETUP_METHOD_NAME = 'initReflector';
|
||||
const REFLECTOR_VAR_NAME = 'reflector';
|
||||
const DEPS_EXTENSION = '.ng_deps.dart';
|
||||
const REFLECTION_CAPABILITIES_NAME = 'ReflectionCapabilities';
|
||||
const REGISTER_TYPE_METHOD_NAME = 'registerType';
|
||||
const REGISTER_GETTERS_METHOD_NAME = 'registerGetters';
|
||||
const REGISTER_SETTERS_METHOD_NAME = 'registerSetters';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
library angular2.transform.common.options;
|
||||
library angular2.transform.common.options_reader;
|
||||
|
||||
import 'package:barback/barback.dart';
|
||||
import 'options.dart';
|
||||
|
|
|
@ -43,7 +43,7 @@ class Parser {
|
|||
Future<List<NgDeps>> _recurse(AssetId id,
|
||||
[List<NgDeps> allDeps, Set<AssetId> seen]) async {
|
||||
if (seen == null) seen = new Set<AssetId>();
|
||||
if (seen.contains(id)) return;
|
||||
if (seen.contains(id)) return null;
|
||||
seen.add(id);
|
||||
|
||||
if (allDeps == null) allDeps = [];
|
||||
|
@ -75,7 +75,6 @@ class NgDeps {
|
|||
|
||||
class _ParseNgDepsVisitor extends Object with RecursiveAstVisitor<Object> {
|
||||
NgDeps ngDeps = null;
|
||||
_RegisteredTypeBuilder current = null;
|
||||
|
||||
@override
|
||||
Object visitImportDirective(ImportDirective node) {
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
library angular2.transform.common;
|
||||
|
||||
import 'package:analyzer/analyzer.dart';
|
||||
import 'package:analyzer/src/generated/java_core.dart';
|
||||
import 'package:analyzer/src/generated/scanner.dart';
|
||||
|
||||
/// Visitor providing common methods for concrete implementations.
|
||||
class VisitorMixin {
|
||||
PrintWriter writer;
|
||||
|
||||
/**
|
||||
* Visit the given function body, printing the prefix before if given body is not empty.
|
||||
*
|
||||
* @param prefix the prefix to be printed if there is a node to visit
|
||||
* @param body the function body to be visited
|
||||
*/
|
||||
void visitFunctionWithPrefix(String prefix, FunctionBody body) {
|
||||
if (body is! EmptyFunctionBody) {
|
||||
writer.print(prefix);
|
||||
}
|
||||
visitNode(body);
|
||||
}
|
||||
|
||||
/// Safely visit [node].
|
||||
void visitNode(AstNode node) {
|
||||
if (node != null) {
|
||||
node.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// Print a list of [nodes] without any separation.
|
||||
void visitNodeList(NodeList<AstNode> nodes) {
|
||||
visitNodeListWithSeparator(nodes, "");
|
||||
}
|
||||
|
||||
/// Print a list of [nodes], separated by the given [separator].
|
||||
void visitNodeListWithSeparator(NodeList<AstNode> nodes, String separator) {
|
||||
if (nodes != null) {
|
||||
int size = nodes.length;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (i > 0) {
|
||||
writer.print(separator);
|
||||
}
|
||||
nodes[i].accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Print a list of [nodes], separated by the given [separator] and
|
||||
/// preceded by the given [prefix].
|
||||
void visitNodeListWithSeparatorAndPrefix(
|
||||
String prefix, NodeList<AstNode> nodes, String separator) {
|
||||
if (nodes != null) {
|
||||
int size = nodes.length;
|
||||
if (size > 0) {
|
||||
writer.print(prefix);
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (i > 0) {
|
||||
writer.print(separator);
|
||||
}
|
||||
nodes[i].accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Print a list of [nodes], separated by the given [separator] and
|
||||
/// succeeded by the given [suffix].
|
||||
void visitNodeListWithSeparatorAndSuffix(
|
||||
NodeList<AstNode> nodes, String separator, String suffix) {
|
||||
if (nodes != null) {
|
||||
int size = nodes.length;
|
||||
if (size > 0) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (i > 0) {
|
||||
writer.print(separator);
|
||||
}
|
||||
nodes[i].accept(this);
|
||||
}
|
||||
writer.print(suffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// If [node] is null does nothing. Otherwise, prints [prefix], then
|
||||
/// visits [node].
|
||||
void visitNodeWithPrefix(String prefix, AstNode node) {
|
||||
if (node != null) {
|
||||
writer.print(prefix);
|
||||
node.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// If [node] is null does nothing. Otherwise, visits [node], then prints
|
||||
/// [suffix].
|
||||
void visitNodeWithSuffix(AstNode node, String suffix) {
|
||||
if (node != null) {
|
||||
node.accept(this);
|
||||
writer.print(suffix);
|
||||
}
|
||||
}
|
||||
|
||||
/// Safely visit [node], printing [suffix] after the node if it is
|
||||
/// non-`null`.
|
||||
void visitTokenWithSuffix(Token token, String suffix) {
|
||||
if (token != null) {
|
||||
writer.print(token.lexeme);
|
||||
writer.print(suffix);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,10 +5,8 @@ import 'package:dart_style/dart_style.dart';
|
|||
|
||||
import 'directive_linker/transformer.dart';
|
||||
import 'directive_processor/transformer.dart';
|
||||
import 'bind_generator/transformer.dart';
|
||||
import 'reflection_remover/transformer.dart';
|
||||
import 'common/formatter.dart' as formatter;
|
||||
import 'common/names.dart';
|
||||
import 'common/options.dart';
|
||||
import 'common/options_reader.dart';
|
||||
|
||||
|
|
|
@ -17,9 +17,10 @@ Future<String> linkNgDeps(AssetReader reader, AssetId entryPoint) async {
|
|||
if (ngDeps == null) return null;
|
||||
if (ngDeps.imports.isEmpty) return ngDeps.code;
|
||||
|
||||
var allDeps = ngDeps.imports.toList()..addAll(ngDeps.exports);
|
||||
var depList = await _processNgImports(
|
||||
reader, entryPoint, allDeps.map((node) => node.uri.stringValue));
|
||||
var depUris = <String>[]
|
||||
..addAll(ngDeps.imports.map((i) => i.uri.stringValue))
|
||||
..addAll(ngDeps.exports.map((i) => i.uri.stringValue));
|
||||
var depList = await _processNgImports(reader, entryPoint, depUris);
|
||||
|
||||
if (depList.isEmpty) return ngDeps.code;
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ import 'package:angular2/src/transform/common/asset_reader.dart';
|
|||
import 'package:angular2/src/transform/common/formatter.dart';
|
||||
import 'package:angular2/src/transform/common/logging.dart' as log;
|
||||
import 'package:angular2/src/transform/common/names.dart';
|
||||
import 'package:angular2/src/transform/common/options.dart';
|
||||
import 'package:barback/barback.dart';
|
||||
|
||||
import 'linker.dart';
|
||||
|
|
|
@ -4,7 +4,6 @@ import 'package:analyzer/analyzer.dart';
|
|||
import 'package:analyzer/src/generated/java_core.dart';
|
||||
import 'package:angular2/src/transform/common/logging.dart';
|
||||
import 'package:angular2/src/transform/common/names.dart';
|
||||
import 'package:angular2/src/transform/common/visitor_mixin.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'visitors.dart';
|
||||
|
@ -27,8 +26,7 @@ String createNgDeps(String code, String path) {
|
|||
|
||||
/// Visitor responsible for processing [CompilationUnit] and creating an
|
||||
/// associated .ng_deps.dart file.
|
||||
class CreateNgDepsVisitor extends Object
|
||||
with SimpleAstVisitor<Object>, VisitorMixin {
|
||||
class CreateNgDepsVisitor extends Object with SimpleAstVisitor<Object> {
|
||||
final PrintWriter writer;
|
||||
final _Tester _tester = const _Tester();
|
||||
bool _foundNgDirectives = false;
|
||||
|
@ -48,11 +46,21 @@ class CreateNgDepsVisitor extends Object
|
|||
_paramsVisitor = new ParameterTransformVisitor(writer),
|
||||
_metaVisitor = new AnnotationsTransformVisitor(writer);
|
||||
|
||||
void _visitNodeListWithSeparator(NodeList<AstNode> list, String separator) {
|
||||
if (list == null) return;
|
||||
for (var i = 0, iLen = list.length; i < iLen; ++i) {
|
||||
if (i != 0) {
|
||||
writer.print(separator);
|
||||
}
|
||||
list[i].accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void visitCompilationUnit(CompilationUnit node) {
|
||||
visitNodeListWithSeparator(node.directives, " ");
|
||||
Object visitCompilationUnit(CompilationUnit node) {
|
||||
_visitNodeListWithSeparator(node.directives, " ");
|
||||
_openFunctionWrapper();
|
||||
visitNodeListWithSeparator(node.declarations, " ");
|
||||
_visitNodeListWithSeparator(node.declarations, " ");
|
||||
_closeFunctionWrapper();
|
||||
return null;
|
||||
}
|
||||
|
@ -139,7 +147,7 @@ class CreateNgDepsVisitor extends Object
|
|||
_foundNgDirectives = true;
|
||||
}
|
||||
writer.print('..registerType(');
|
||||
visitNode(node.name);
|
||||
node.name.accept(this);
|
||||
writer.print(''', {'factory': ''');
|
||||
if (ctor == null) {
|
||||
_generateEmptyFactory(node.name.toString());
|
||||
|
@ -155,9 +163,8 @@ class CreateNgDepsVisitor extends Object
|
|||
writer.print(''', 'annotations': ''');
|
||||
node.accept(_metaVisitor);
|
||||
writer.print('})');
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Object _nodeToSource(AstNode node) {
|
||||
|
|
|
@ -3,10 +3,9 @@ library angular2.transform.directive_processor;
|
|||
import 'package:analyzer/analyzer.dart';
|
||||
import 'package:analyzer/src/generated/java_core.dart';
|
||||
import 'package:angular2/src/transform/common/logging.dart';
|
||||
import 'package:angular2/src/transform/common/visitor_mixin.dart';
|
||||
|
||||
/// SourceVisitor designed to accept [ConstructorDeclaration] nodes.
|
||||
class _CtorTransformVisitor extends ToSourceVisitor with VisitorMixin {
|
||||
/// `ToSourceVisitor` designed to accept [ConstructorDeclaration] nodes.
|
||||
class _CtorTransformVisitor extends ToSourceVisitor {
|
||||
bool _withParameterAnnotations = true;
|
||||
bool _withParameterTypes = true;
|
||||
bool _withParameterNames = true;
|
||||
|
@ -20,25 +19,50 @@ class _CtorTransformVisitor extends ToSourceVisitor with VisitorMixin {
|
|||
: this.writer = writer,
|
||||
super(writer);
|
||||
|
||||
void _visitNodeWithPrefix(String prefix, AstNode node) {
|
||||
if (node != null) {
|
||||
writer.print(prefix);
|
||||
node.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void _visitNodeWithSuffix(AstNode node, String suffix) {
|
||||
if (node != null) {
|
||||
node.accept(this);
|
||||
writer.print(suffix);
|
||||
}
|
||||
}
|
||||
|
||||
void _visitNode(AstNode node) {
|
||||
if (node != null) {
|
||||
node.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// If [_withParameterTypes] is true, this method outputs [node]'s type. If
|
||||
/// [_withParameterNames] is true, this method outputs [node]'s identifier.
|
||||
Object _visitNormalFormalParameter(
|
||||
NodeList<Annotation> metadata, TypeName type, SimpleIdentifier name) {
|
||||
if (_withParameterAnnotations && metadata != null) {
|
||||
assert(_withParameterTypes);
|
||||
var suffix = type != null ? ', ' : '';
|
||||
visitNodeListWithSeparatorAndSuffix(metadata, ', ', suffix);
|
||||
for (var i = 0, iLen = metadata.length; i < iLen; ++i) {
|
||||
if (i != 0) {
|
||||
writer.print(', ');
|
||||
}
|
||||
metadata[i].accept(this);
|
||||
}
|
||||
writer.print(type != null && metadata.isNotEmpty ? ', ' : '');
|
||||
}
|
||||
var needCompileTimeConstants = !_withParameterNames;
|
||||
if (_withParameterTypes && type != null) {
|
||||
visitNodeWithSuffix(type.name, ' ');
|
||||
_visitNodeWithSuffix(type.name, ' ');
|
||||
if (!needCompileTimeConstants) {
|
||||
// Types with arguments are not compile-time constants.
|
||||
visitNodeWithSuffix(type.typeArguments, ' ');
|
||||
_visitNodeWithSuffix(type.typeArguments, ' ');
|
||||
}
|
||||
}
|
||||
if (_withParameterNames) {
|
||||
visitNode(name);
|
||||
_visitNode(name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -87,7 +111,7 @@ class _CtorTransformVisitor extends ToSourceVisitor with VisitorMixin {
|
|||
|
||||
@override
|
||||
Object visitDefaultFormalParameter(DefaultFormalParameter node) {
|
||||
visitNode(node.parameter);
|
||||
_visitNode(node.parameter);
|
||||
// Ignore the declared default value.
|
||||
return null;
|
||||
}
|
||||
|
@ -112,9 +136,9 @@ class _CtorTransformVisitor extends ToSourceVisitor with VisitorMixin {
|
|||
Object visitAnnotation(Annotation node) {
|
||||
var prefix =
|
||||
node.arguments != null && node.arguments.length > 0 ? 'const ' : '';
|
||||
visitNodeWithPrefix(prefix, node.name);
|
||||
visitNodeWithPrefix(".", node.constructorName);
|
||||
visitNode(node.arguments);
|
||||
_visitNodeWithPrefix(prefix, node.name);
|
||||
_visitNodeWithPrefix(".", node.constructorName);
|
||||
_visitNode(node.arguments);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +156,7 @@ class ParameterTransformVisitor extends _CtorTransformVisitor {
|
|||
Object visitConstructorDeclaration(ConstructorDeclaration node) {
|
||||
_buildFieldMap(node);
|
||||
writer.print('const [');
|
||||
visitNode(node.parameters);
|
||||
_visitNode(node.parameters);
|
||||
writer.print(']');
|
||||
return null;
|
||||
}
|
||||
|
@ -140,8 +164,7 @@ class ParameterTransformVisitor extends _CtorTransformVisitor {
|
|||
@override
|
||||
Object visitFormalParameterList(FormalParameterList node) {
|
||||
NodeList<FormalParameter> parameters = node.parameters;
|
||||
int size = parameters.length;
|
||||
for (int i = 0; i < size; i++) {
|
||||
for (int i = 0, iLen = parameters.length; i < iLen; i++) {
|
||||
if (i > 0) {
|
||||
writer.print(', ');
|
||||
}
|
||||
|
@ -166,20 +189,20 @@ class FactoryTransformVisitor extends _CtorTransformVisitor {
|
|||
_buildFieldMap(node);
|
||||
_withParameterNames = true;
|
||||
_withParameterTypes = true;
|
||||
visitNode(node.parameters);
|
||||
_visitNode(node.parameters);
|
||||
writer.print(' => new ');
|
||||
visitNode(node.returnType);
|
||||
visitNodeWithPrefix(".", node.name);
|
||||
_visitNode(node.returnType);
|
||||
_visitNodeWithPrefix(".", node.name);
|
||||
|
||||
_withParameterTypes = false;
|
||||
visitNode(node.parameters);
|
||||
_visitNode(node.parameters);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// ToSourceVisitor designed to print a [ClassDeclaration] node as a
|
||||
/// 'annotations' value for Angular2's [registerType] calls.
|
||||
class AnnotationsTransformVisitor extends ToSourceVisitor with VisitorMixin {
|
||||
class AnnotationsTransformVisitor extends ToSourceVisitor {
|
||||
final PrintWriter writer;
|
||||
AnnotationsTransformVisitor(PrintWriter writer)
|
||||
: this.writer = writer,
|
||||
|
@ -202,9 +225,16 @@ class AnnotationsTransformVisitor extends ToSourceVisitor with VisitorMixin {
|
|||
@override
|
||||
Object visitAnnotation(Annotation node) {
|
||||
writer.print('const ');
|
||||
visitNode(node.name);
|
||||
visitNodeWithPrefix(".", node.constructorName);
|
||||
visitNode(node.arguments);
|
||||
if (node.name != null) {
|
||||
node.name.accept(this);
|
||||
}
|
||||
if (node.constructorName != null) {
|
||||
writer.print('.');
|
||||
node.constructorName.accept(this);
|
||||
}
|
||||
if (node.arguments != null) {
|
||||
node.arguments.accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
library angular2.transform;
|
||||
|
||||
import 'dart:collection' show Queue;
|
||||
import 'package:analyzer/src/generated/ast.dart';
|
||||
import 'package:analyzer/src/generated/element.dart';
|
||||
|
||||
import 'resolvers.dart';
|
||||
|
||||
/// Provides a mechanism for checking an element for the provided
|
||||
/// [_annotationClass] and reporting the resulting (element, annotation) pairs.
|
||||
class AnnotationMatcher {
|
||||
/// Queue for annotations.
|
||||
final matchQueue = new Queue<AnnotationMatch>();
|
||||
/// All the annotations we have seen for each element
|
||||
final _seenAnnotations = new Map<Element, Set<ElementAnnotation>>();
|
||||
|
||||
/// The classes we are searching for to populate [matchQueue].
|
||||
final Set<ClassElement> _annotationClasses;
|
||||
|
||||
AnnotationMatcher(this._annotationClasses);
|
||||
|
||||
/// Records all [_annotationClass] annotations and the [element]s they apply to.
|
||||
/// Returns
|
||||
List<AnnotationMatch> processAnnotations(ClassElement element) {
|
||||
// Finding the node corresponding to [element] can be very expensive.
|
||||
ClassDeclaration cachedNode = null;
|
||||
|
||||
var result = <AnnotationMatch>[];
|
||||
element.metadata.where((ElementAnnotation meta) {
|
||||
// TODO(tjblasi): Make this recognize non-ConstructorElement annotations.
|
||||
return meta.element is ConstructorElement &&
|
||||
_isAnnotationMatch(meta.element.returnType);
|
||||
}).where((ElementAnnotation meta) {
|
||||
// Only process ([element], [meta]) combinations we haven't seen previously.
|
||||
return !_seenAnnotations
|
||||
.putIfAbsent(element, () => new Set<ElementAnnotation>())
|
||||
.contains(meta);
|
||||
}).forEach((ElementAnnotation meta) {
|
||||
if (cachedNode == null) {
|
||||
cachedNode = element.node;
|
||||
}
|
||||
|
||||
var match = new AnnotationMatch(cachedNode, meta);
|
||||
_seenAnnotations[element].add(meta);
|
||||
matchQueue.addLast(match);
|
||||
result.add(match);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Whether [type], its superclass, or one of its interfaces matches [_annotationClass].
|
||||
bool _isAnnotationMatch(InterfaceType type) {
|
||||
return _annotationClasses.any((el) => isAnnotationMatch(type, el));
|
||||
}
|
||||
}
|
||||
|
||||
/// [ClassElement] / [ElementAnnotation] pair.
|
||||
class AnnotationMatch {
|
||||
/// The resolved element corresponding to [node].
|
||||
final ClassElement element;
|
||||
|
||||
/// The Ast node corresponding to the class definition.
|
||||
final ClassDeclaration node;
|
||||
|
||||
/// The resolved element for the matched annotation.
|
||||
final ElementAnnotation annotation;
|
||||
|
||||
AnnotationMatch(ClassDeclaration node, this.annotation)
|
||||
: node = node,
|
||||
element = node.element;
|
||||
}
|
|
@ -1,518 +0,0 @@
|
|||
library angular2.transform;
|
||||
|
||||
import 'package:analyzer/src/generated/ast.dart';
|
||||
import 'package:analyzer/src/generated/element.dart';
|
||||
import 'package:analyzer/src/generated/java_core.dart';
|
||||
import 'package:barback/barback.dart' show AssetId, TransformLogger;
|
||||
import 'package:dart_style/dart_style.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'annotation_processor.dart';
|
||||
import 'common/logging.dart';
|
||||
|
||||
/// Base class that maintains codegen state.
|
||||
class Context {
|
||||
/// Maps libraries to the import prefixes we will use in the newly
|
||||
/// generated code.
|
||||
final Map<LibraryElement, String> _libraryPrefixes = {};
|
||||
|
||||
/// Whether to generate constructor stubs for classes annotated
|
||||
/// with [Component], [Decorator], [View], and [Inject] (and subtypes).
|
||||
bool generateCtorStubs = true;
|
||||
|
||||
/// Whether to generate setter stubs for classes annotated with
|
||||
/// [Directive] subtypes. These setters depend on the value passed to the
|
||||
/// annotation's `properties` value.
|
||||
bool generateSetterStubs = true;
|
||||
|
||||
DirectiveRegistry _directiveRegistry;
|
||||
/// Generates [registerType] calls for all [register]ed [AnnotationMatch]
|
||||
/// objects.
|
||||
DirectiveRegistry get directiveRegistry => _directiveRegistry;
|
||||
|
||||
Context() {
|
||||
_directiveRegistry = new _DirectiveRegistryImpl(this);
|
||||
}
|
||||
|
||||
/// If elements in [lib] should be prefixed in our generated code, returns
|
||||
/// the appropriate prefix followed by a `.`. Future items from the same
|
||||
/// library will use the same prefix.
|
||||
/// If [lib] does not need a prefix, returns the empty string.
|
||||
String _getPrefixDot(LibraryElement lib) {
|
||||
if (lib == null || lib.isInSdk) return '';
|
||||
var prefix =
|
||||
_libraryPrefixes.putIfAbsent(lib, () => 'i${_libraryPrefixes.length}');
|
||||
return '${prefix}.';
|
||||
}
|
||||
}
|
||||
|
||||
/// Object which [register]s [AnnotationMatch] objects for code generation.
|
||||
abstract class DirectiveRegistry {
|
||||
// Adds [entry] to the `registerType` calls which will be generated.
|
||||
void register(AnnotationMatch entry);
|
||||
}
|
||||
|
||||
const setupReflectionMethodName = 'setupReflection';
|
||||
|
||||
const _libraryDeclaration = '''
|
||||
library angular2.transform.generated;
|
||||
''';
|
||||
|
||||
const _reflectorImport = '''
|
||||
import 'package:angular2/src/reflection/reflection.dart' show reflector;
|
||||
''';
|
||||
|
||||
/// Default implementation to map from [LibraryElement] to [AssetId]. This
|
||||
/// assumes that [el.source] has a getter called [assetId].
|
||||
AssetId _assetIdFromLibraryElement(LibraryElement el) {
|
||||
return (el.source as dynamic).assetId;
|
||||
}
|
||||
|
||||
String codegenEntryPoint(Context context, {AssetId newEntryPoint}) {
|
||||
if (newEntryPoint == null) {
|
||||
throw new ArgumentError.notNull('newEntryPoint');
|
||||
}
|
||||
// TODO(kegluneq): copyright declaration
|
||||
var outBuffer = new StringBuffer()
|
||||
..write(_libraryDeclaration)
|
||||
..write(_reflectorImport);
|
||||
_codegenImports(context, newEntryPoint, outBuffer);
|
||||
outBuffer
|
||||
.write('${setupReflectionMethodName}() {${context.directiveRegistry}}');
|
||||
|
||||
return new DartFormatter().format(outBuffer.toString());
|
||||
}
|
||||
|
||||
void _codegenImports(
|
||||
Context context, AssetId newEntryPoint, StringBuffer buffer) {
|
||||
context._libraryPrefixes.forEach((lib, prefix) {
|
||||
buffer
|
||||
..write(_codegenImport(
|
||||
context, _assetIdFromLibraryElement(lib), newEntryPoint))
|
||||
..writeln('as ${prefix};');
|
||||
});
|
||||
}
|
||||
|
||||
String _codegenImport(Context context, AssetId libraryId, AssetId entryPoint) {
|
||||
if (libraryId.path.startsWith('lib/')) {
|
||||
var packagePath = libraryId.path.replaceFirst('lib/', '');
|
||||
return "import 'package:${libraryId.package}/${packagePath}'";
|
||||
} else if (libraryId.package != entryPoint.package) {
|
||||
logger.error("Can't import `${libraryId}` from `${entryPoint}`");
|
||||
} else if (path.url.split(libraryId.path)[0] ==
|
||||
path.url.split(entryPoint.path)[0]) {
|
||||
var relativePath =
|
||||
path.relative(libraryId.path, from: path.dirname(entryPoint.path));
|
||||
return "import '${relativePath}'";
|
||||
} else {
|
||||
logger.error("Can't import `${libraryId}` from `${entryPoint}`");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(https://github.com/kegluneq/angular/issues/4): Remove calls to
|
||||
// Element#node.
|
||||
class _DirectiveRegistryImpl implements DirectiveRegistry {
|
||||
final Context _context;
|
||||
final PrintWriter _writer;
|
||||
final Set<ClassDeclaration> _seen = new Set();
|
||||
final _AnnotationsTransformVisitor _annotationsVisitor;
|
||||
final _BindTransformVisitor _bindVisitor;
|
||||
final _FactoryTransformVisitor _factoryVisitor;
|
||||
final _ParameterTransformVisitor _parametersVisitor;
|
||||
|
||||
_DirectiveRegistryImpl._internal(Context context, PrintWriter writer)
|
||||
: _writer = writer,
|
||||
_context = context,
|
||||
_annotationsVisitor = new _AnnotationsTransformVisitor(writer, context),
|
||||
_bindVisitor = new _BindTransformVisitor(writer, context),
|
||||
_factoryVisitor = new _FactoryTransformVisitor(writer, context),
|
||||
_parametersVisitor = new _ParameterTransformVisitor(writer, context);
|
||||
|
||||
factory _DirectiveRegistryImpl(Context context) {
|
||||
return new _DirectiveRegistryImpl._internal(
|
||||
context, new PrintStringWriter());
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return _seen.isEmpty ? '' : 'reflector${_writer};';
|
||||
}
|
||||
|
||||
// Adds [entry] to the `registerType` calls which will be generated.
|
||||
void register(AnnotationMatch entry) {
|
||||
if (_seen.contains(entry.node)) return;
|
||||
_seen.add(entry.node);
|
||||
|
||||
if (_context.generateCtorStubs) {
|
||||
_generateCtorStubs(entry);
|
||||
}
|
||||
if (_context.generateSetterStubs) {
|
||||
_generateSetterStubs(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void _generateSetterStubs(AnnotationMatch entry) {
|
||||
// TODO(kegluneq): Remove these requirements for setter stub generation.
|
||||
if (entry.element is! ClassElement) {
|
||||
logger.error('Directives can only be applied to classes.');
|
||||
return;
|
||||
}
|
||||
if (entry.node is! ClassDeclaration) {
|
||||
logger.error('Unsupported annotation type for ctor stub generation. '
|
||||
'Only class declarations are supported as Directives.');
|
||||
return;
|
||||
}
|
||||
|
||||
entry.node.accept(_bindVisitor);
|
||||
}
|
||||
|
||||
void _generateCtorStubs(AnnotationMatch entry) {
|
||||
var element = entry.element;
|
||||
var annotation = entry.annotation;
|
||||
|
||||
// TODO(kegluneq): Remove these requirements for ctor stub generation.
|
||||
if (annotation.element is! ConstructorElement) {
|
||||
logger.error('Unsupported annotation type for ctor stub generation. '
|
||||
'Only constructors are supported as Directives.');
|
||||
return;
|
||||
}
|
||||
if (element is! ClassElement) {
|
||||
logger.error('Directives can only be applied to classes.');
|
||||
return;
|
||||
}
|
||||
if (entry.node is! ClassDeclaration) {
|
||||
logger.error('Unsupported annotation type for ctor stub generation. '
|
||||
'Only class declarations are supported as Directives.');
|
||||
return;
|
||||
}
|
||||
var ctor = element.unnamedConstructor;
|
||||
if (ctor == null) {
|
||||
logger.error('No unnamed constructor found for ${element.name}');
|
||||
return;
|
||||
}
|
||||
var ctorNode = ctor.node;
|
||||
|
||||
_writer.print('..registerType(');
|
||||
_codegenClassTypeString(element);
|
||||
_writer.print(', {"factory": ');
|
||||
_codegenClassTypeString(element);
|
||||
_writer.print('.ngFactory');
|
||||
_writer.print(', "parameters": ');
|
||||
_codegenClassTypeString(element);
|
||||
_writer.print('.ngParameters');
|
||||
_writer.print(', "annotations": ');
|
||||
_codegenClassTypeString(element);
|
||||
_writer.print('.ngAnnotations');
|
||||
_writer.print('})');
|
||||
}
|
||||
|
||||
void _codegenClassTypeString(ClassElement el) {
|
||||
_writer.print('${_context._getPrefixDot(el.library)}${el.name}');
|
||||
}
|
||||
|
||||
/// Creates the 'annotations' property for the Angular2 [registerType] call
|
||||
/// for [node].
|
||||
void _codegenAnnotationsProp(ClassDeclaration node) {
|
||||
node.accept(_annotationsVisitor);
|
||||
}
|
||||
|
||||
/// Creates the 'factory' property for the Angular2 [registerType] call
|
||||
/// for [node]. [element] is necessary if [node] is null.
|
||||
void _codegenFactoryProp(ConstructorDeclaration node, ClassElement element) {
|
||||
if (node == null) {
|
||||
// This occurs when the class does not declare a constructor.
|
||||
var prefix = _context._getPrefixDot(element.library);
|
||||
_writer.print('() => new ${prefix}${element.displayName}()');
|
||||
} else {
|
||||
node.accept(_factoryVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates the 'parameters' property for the Angular2 [registerType] call
|
||||
/// for [node].
|
||||
void _codegenParametersProp(ConstructorDeclaration node) {
|
||||
if (node == null) {
|
||||
// This occurs when the class does not declare a constructor.
|
||||
_writer.print('const [const []]');
|
||||
} else {
|
||||
node.accept(_parametersVisitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Visitor providing common methods for concrete implementations.
|
||||
class _TransformVisitorMixin {
|
||||
final Context context;
|
||||
final PrintWriter writer;
|
||||
|
||||
/// Safely visit [node].
|
||||
void _visitNode(AstNode node) {
|
||||
if (node != null) {
|
||||
node.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// If [node] is null does nothing. Otherwise, prints [prefix], then
|
||||
/// visits [node].
|
||||
void _visitNodeWithPrefix(String prefix, AstNode node) {
|
||||
if (node != null) {
|
||||
writer.print(prefix);
|
||||
node.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// If [node] is null does nothing. Otherwise, visits [node], then prints
|
||||
/// [suffix].
|
||||
void _visitNodeWithSuffix(AstNode node, String suffix) {
|
||||
if (node != null) {
|
||||
node.accept(this);
|
||||
writer.print(suffix);
|
||||
}
|
||||
}
|
||||
|
||||
String prefixedSimpleIdentifier(SimpleIdentifier node) {
|
||||
// Make sure the identifier is prefixed if necessary.
|
||||
if (node.bestElement is ClassElementImpl ||
|
||||
node.bestElement is PropertyAccessorElement) {
|
||||
return context._getPrefixDot(node.bestElement.library) +
|
||||
node.token.lexeme;
|
||||
} else {
|
||||
return node.token.lexeme;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _TransformVisitor extends ToSourceVisitor with _TransformVisitorMixin {
|
||||
final Context context;
|
||||
final PrintWriter writer;
|
||||
|
||||
_TransformVisitor(PrintWriter writer, this.context)
|
||||
: this.writer = writer,
|
||||
super(writer);
|
||||
|
||||
@override
|
||||
Object visitPrefixedIdentifier(PrefixedIdentifier node) {
|
||||
// We add our own prefixes in [visitSimpleIdentifier], discard any used in
|
||||
// the original source.
|
||||
writer.print(super.prefixedSimpleIdentifier(node.identifier));
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitSimpleIdentifier(SimpleIdentifier node) {
|
||||
writer.print(super.prefixedSimpleIdentifier(node));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// SourceVisitor designed to accept [ConstructorDeclaration] nodes.
|
||||
class _CtorTransformVisitor extends _TransformVisitor {
|
||||
bool _withParameterTypes = true;
|
||||
bool _withParameterNames = true;
|
||||
|
||||
_CtorTransformVisitor(PrintWriter writer, Context _context)
|
||||
: super(writer, _context);
|
||||
|
||||
/// If [_withParameterTypes] is true, this method outputs [node]'s type
|
||||
/// (appropriately prefixed based on [_libraryPrefixes]. If
|
||||
/// [_withParameterNames] is true, this method outputs [node]'s identifier.
|
||||
Object _visitNormalFormalParameter(NormalFormalParameter node) {
|
||||
if (_withParameterTypes) {
|
||||
var paramType = node.element.type;
|
||||
var prefix = context._getPrefixDot(paramType.element.library);
|
||||
writer.print('${prefix}${paramType.displayName}');
|
||||
if (_withParameterNames) {
|
||||
_visitNodeWithPrefix(' ', node.identifier);
|
||||
}
|
||||
} else if (_withParameterNames) {
|
||||
_visitNode(node.identifier);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitSimpleFormalParameter(SimpleFormalParameter node) {
|
||||
return _visitNormalFormalParameter(node);
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitFieldFormalParameter(FieldFormalParameter node) {
|
||||
if (node.parameters != null) {
|
||||
logger.error('Parameters in ctor not supported '
|
||||
'(${super.visitFormalParameterList(node)}');
|
||||
}
|
||||
return _visitNormalFormalParameter(node);
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitDefaultFormalParameter(DefaultFormalParameter node) {
|
||||
_visitNode(node.parameter);
|
||||
// Ignore the declared default value.
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
/// Overridden to avoid outputting grouping operators for default parameters.
|
||||
Object visitFormalParameterList(FormalParameterList node) {
|
||||
writer.print('(');
|
||||
NodeList<FormalParameter> parameters = node.parameters;
|
||||
int size = parameters.length;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (i > 0) {
|
||||
writer.print(', ');
|
||||
}
|
||||
parameters[i].accept(this);
|
||||
}
|
||||
writer.print(')');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// ToSourceVisitor designed to print 'parameters' values for Angular2's
|
||||
/// [registerType] calls.
|
||||
class _ParameterTransformVisitor extends _CtorTransformVisitor {
|
||||
_ParameterTransformVisitor(PrintWriter writer, Context _context)
|
||||
: super(writer, _context);
|
||||
|
||||
@override
|
||||
Object visitConstructorDeclaration(ConstructorDeclaration node) {
|
||||
_withParameterNames = false;
|
||||
_withParameterTypes = true;
|
||||
writer.print('const [const [');
|
||||
_visitNode(node.parameters);
|
||||
writer.print(']]');
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitFormalParameterList(FormalParameterList node) {
|
||||
NodeList<FormalParameter> parameters = node.parameters;
|
||||
int size = parameters.length;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (i > 0) {
|
||||
writer.print(', ');
|
||||
}
|
||||
parameters[i].accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// ToSourceVisitor designed to print 'factory' values for Angular2's
|
||||
/// [registerType] calls.
|
||||
class _FactoryTransformVisitor extends _CtorTransformVisitor {
|
||||
_FactoryTransformVisitor(PrintWriter writer, Context _context)
|
||||
: super(writer, _context);
|
||||
|
||||
@override
|
||||
Object visitConstructorDeclaration(ConstructorDeclaration node) {
|
||||
_withParameterNames = true;
|
||||
_withParameterTypes = true;
|
||||
_visitNode(node.parameters);
|
||||
writer.print(' => new ');
|
||||
_visitNode(node.returnType);
|
||||
_visitNodeWithPrefix(".", node.name);
|
||||
_withParameterTypes = false;
|
||||
_visitNode(node.parameters);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// ToSourceVisitor designed to print a [ClassDeclaration] node as a
|
||||
/// 'annotations' value for Angular2's [registerType] calls.
|
||||
class _AnnotationsTransformVisitor extends _TransformVisitor {
|
||||
_AnnotationsTransformVisitor(PrintWriter writer, Context _context)
|
||||
: super(writer, _context);
|
||||
|
||||
@override
|
||||
Object visitClassDeclaration(ClassDeclaration node) {
|
||||
writer.print('const [');
|
||||
var size = node.metadata.length;
|
||||
for (var i = 0; i < size; ++i) {
|
||||
if (i > 0) {
|
||||
writer.print(', ');
|
||||
}
|
||||
node.metadata[i].accept(this);
|
||||
}
|
||||
writer.print(']');
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitAnnotation(Annotation node) {
|
||||
writer.print('const ');
|
||||
_visitNode(node.name);
|
||||
// TODO(tjblasi): Do we need to handle named constructors for annotations?
|
||||
// _visitNodeWithPrefix(".", node.constructorName);
|
||||
_visitNode(node.arguments);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Visitor designed to print a [ClassDeclaration] node as a
|
||||
/// `registerSetters` call for Angular2.
|
||||
class _BindTransformVisitor extends Object
|
||||
with SimpleAstVisitor<Object>, _TransformVisitorMixin {
|
||||
final Context context;
|
||||
final PrintWriter writer;
|
||||
final List<String> _bindPieces = [];
|
||||
SimpleIdentifier _currentName = null;
|
||||
|
||||
_BindTransformVisitor(this.writer, this.context);
|
||||
|
||||
@override
|
||||
Object visitClassDeclaration(ClassDeclaration node) {
|
||||
_currentName = node.name;
|
||||
node.metadata.forEach((meta) => _visitNode(meta));
|
||||
if (_bindPieces.isNotEmpty) {
|
||||
writer.print('..registerSetters({${_bindPieces.join(', ')}})');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitAnnotation(Annotation node) {
|
||||
// TODO(kegluneq): Remove this restriction.
|
||||
if (node.element is ConstructorElement) {
|
||||
if (node.element.returnType.element is ClassElement) {
|
||||
// TODO(kegluneq): Check if this is actually a `directive`.
|
||||
node.arguments.arguments.forEach((arg) => _visitNode(arg));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitNamedExpression(NamedExpression node) {
|
||||
if (node.name.label.toString() == 'bind') {
|
||||
// TODO(kegluneq): Remove this restriction.
|
||||
if (node.expression is MapLiteral) {
|
||||
node.expression.accept(this);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitMapLiteral(MapLiteral node) {
|
||||
node.entries.forEach((entry) {
|
||||
if (entry.key is SimpleStringLiteral) {
|
||||
_visitNode(entry.key);
|
||||
} else {
|
||||
logger.error('`properties` currently only supports string literals');
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitSimpleStringLiteral(SimpleStringLiteral node) {
|
||||
if (_currentName == null) {
|
||||
logger.error('Unexpected code path: `currentName` should never be null');
|
||||
}
|
||||
_bindPieces.add('"${node.value}": ('
|
||||
'${super.prefixedSimpleIdentifier(_currentName)} o, String value) => '
|
||||
'o.${node.value} = value');
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
library angular2.transform;
|
||||
|
||||
import 'package:analyzer/src/generated/ast.dart';
|
||||
import 'package:analyzer/src/generated/element.dart';
|
||||
import 'package:code_transformers/resolver.dart';
|
||||
|
||||
import 'resolvers.dart';
|
||||
|
||||
/// Finds all calls to the Angular2 [bootstrap] method defined in [library].
|
||||
/// This only searches the code defined in the file
|
||||
// represented by [library], not `part`s, `import`s, `export`s, etc.
|
||||
Set<BootstrapCallInfo> findBootstrapCalls(
|
||||
Resolver resolver, LibraryElement library) {
|
||||
var types = new Angular2Types(resolver);
|
||||
if (types.bootstrapMethod == null) {
|
||||
throw new ArgumentError(
|
||||
'Could not find symbol for ${bootstrapMethodName}.');
|
||||
}
|
||||
var visitor = new _FindFunctionVisitor(types.bootstrapMethod);
|
||||
|
||||
// TODO(kegluneq): Determine how to get nodes without querying Element#node.
|
||||
// Root of file defining that library (main part).
|
||||
library.definingCompilationUnit.node.accept(visitor);
|
||||
|
||||
return new Set.from(visitor.functionCalls.map((MethodInvocation mi) {
|
||||
var visitor = new _ParseBootstrapTypeVisitor(types);
|
||||
if (mi.argumentList.arguments.isEmpty) {
|
||||
throw new ArgumentError('No arguments provided to `bootstrap`.');
|
||||
}
|
||||
mi.argumentList.arguments[0].accept(visitor);
|
||||
if (visitor.bootstrapType == null) {
|
||||
throw new UnsupportedError(
|
||||
'Failed to parse `bootstrap` call: ${mi.toSource()}');
|
||||
}
|
||||
return new BootstrapCallInfo(mi, visitor.bootstrapType);
|
||||
}));
|
||||
}
|
||||
|
||||
/// Information about a single call to Angular2's [bootstrap] method.
|
||||
class BootstrapCallInfo {
|
||||
/// The [AstNode] representing the call to [bootstrap].
|
||||
final MethodInvocation call;
|
||||
|
||||
/// The type, which should be annotated as a [Component], which is the root
|
||||
/// of the Angular2 app.
|
||||
final ClassElement bootstrapType;
|
||||
|
||||
BootstrapCallInfo(this.call, this.bootstrapType);
|
||||
}
|
||||
|
||||
/// Visitor that finds the Angular2 bootstrap component given [bootstrap]'s
|
||||
/// first argument.
|
||||
///
|
||||
/// This visitor does not recursively visit nodes in the Ast.
|
||||
class _ParseBootstrapTypeVisitor extends SimpleAstVisitor<Object> {
|
||||
ClassElement bootstrapType = null;
|
||||
|
||||
final Angular2Types _types;
|
||||
|
||||
_ParseBootstrapTypeVisitor(this._types);
|
||||
|
||||
// TODO(kegluneq): Allow non-SimpleIdentifier expressions.
|
||||
|
||||
@override
|
||||
Object visitSimpleIdentifier(SimpleIdentifier node) {
|
||||
bootstrapType = (node.bestElement as ClassElement);
|
||||
if (!_types.isComponent(bootstrapType)) {
|
||||
throw new ArgumentError('Class passed to `${bootstrapMethodName}` must '
|
||||
'be a @${_types.componentAnnotation.name}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Recursively visits all nodes in an Ast structure, recording all encountered
|
||||
/// calls to the provided [FunctionElement].
|
||||
class _FindFunctionVisitor extends RecursiveAstVisitor<Object> {
|
||||
final FunctionElement _target;
|
||||
_FindFunctionVisitor(this._target);
|
||||
|
||||
final Set<MethodInvocation> functionCalls = new Set();
|
||||
|
||||
bool _isDesiredMethod(MethodInvocation node) {
|
||||
return node.methodName.bestElement == _target;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitMethodInvocation(MethodInvocation node) {
|
||||
if (_isDesiredMethod(node)) {
|
||||
functionCalls.add(node);
|
||||
}
|
||||
return super.visitMethodInvocation(node);
|
||||
}
|
||||
}
|
|
@ -1,152 +0,0 @@
|
|||
library angular2.transform;
|
||||
|
||||
import 'package:analyzer/src/generated/ast.dart';
|
||||
import 'package:analyzer/src/generated/element.dart';
|
||||
import 'package:analyzer/src/generated/java_core.dart';
|
||||
import 'package:barback/barback.dart';
|
||||
import 'package:code_transformers/resolver.dart';
|
||||
import 'package:dart_style/dart_style.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'codegen.dart';
|
||||
import 'common/logging.dart';
|
||||
import 'resolvers.dart';
|
||||
|
||||
/// Finds all calls to the Angular2 [ReflectionCapabilities] constructor
|
||||
/// defined in [library].
|
||||
/// This only searches the code defined in the file
|
||||
// represented by [library], not `part`s, `import`s, `export`s, etc.
|
||||
String findReflectionCapabilities(
|
||||
Resolver resolver, AssetId reflectionEntryPoint, AssetId newEntryPoint) {
|
||||
var types = new Angular2Types(resolver);
|
||||
if (types.reflectionCapabilities == null) {
|
||||
throw new ArgumentError(
|
||||
'Could not find class for ${reflectionCapabilitiesTypeName}.');
|
||||
}
|
||||
|
||||
var codegen = new _SetupReflectionCodegen(
|
||||
resolver, reflectionEntryPoint, newEntryPoint);
|
||||
|
||||
var writer = new PrintStringWriter();
|
||||
var visitor = new _RewriteReflectionEntryPointVisitor(
|
||||
writer, types.reflectionCapabilities, codegen);
|
||||
|
||||
// TODO(kegluneq): Determine how to get nodes without querying Element#node.
|
||||
// Root of file defining that library (main part).
|
||||
resolver.getLibrary(reflectionEntryPoint).definingCompilationUnit.node
|
||||
.accept(visitor);
|
||||
|
||||
return new DartFormatter().format(writer.toString());
|
||||
}
|
||||
|
||||
class _SetupReflectionCodegen {
|
||||
static const _prefixBase = 'ngStaticInit';
|
||||
|
||||
final String prefix;
|
||||
final String importUri;
|
||||
|
||||
_SetupReflectionCodegen._internal(this.prefix, this.importUri);
|
||||
|
||||
factory _SetupReflectionCodegen(
|
||||
Resolver resolver, AssetId reflectionEntryPoint, AssetId newEntryPoint) {
|
||||
var lib = resolver.getLibrary(reflectionEntryPoint);
|
||||
var prefix = _prefixBase;
|
||||
var idx = 0;
|
||||
while (lib.imports.any((import) {
|
||||
return import.prefix != null && import.prefix == prefix;
|
||||
})) {
|
||||
prefix = '${_prefixBase}${idx++}';
|
||||
}
|
||||
|
||||
var importPath = path.relative(newEntryPoint.path,
|
||||
from: path.dirname(reflectionEntryPoint.path));
|
||||
return new _SetupReflectionCodegen._internal(prefix, importPath);
|
||||
}
|
||||
|
||||
/// Generates code to import the library containing the method which sets up
|
||||
/// Angular2 reflection statically.
|
||||
///
|
||||
/// The code generated here should follow the example of code generated for
|
||||
/// an [ImportDirective] node.
|
||||
String codegenImport() {
|
||||
return 'import \'${importUri}\' as ${prefix};';
|
||||
}
|
||||
|
||||
/// Generates code to call the method which sets up Angular2 reflection
|
||||
/// statically.
|
||||
///
|
||||
/// The code generated here should follow the example of code generated for
|
||||
/// a [MethodInvocation] node, that is, it should be prefixed as necessary
|
||||
/// and not be followed by a ';'.
|
||||
String codegenSetupReflectionCall() {
|
||||
return '${prefix}.${setupReflectionMethodName}()';
|
||||
}
|
||||
}
|
||||
|
||||
class _RewriteReflectionEntryPointVisitor extends ToSourceVisitor {
|
||||
final PrintWriter _writer;
|
||||
final ClassElement _forbiddenClass;
|
||||
final _SetupReflectionCodegen _codegen;
|
||||
|
||||
_RewriteReflectionEntryPointVisitor(
|
||||
PrintWriter writer, this._forbiddenClass, this._codegen)
|
||||
: _writer = writer,
|
||||
super(writer);
|
||||
|
||||
bool _isNewReflectionCapabilities(InstanceCreationExpression node) {
|
||||
var typeElement = node.constructorName.type.name.bestElement;
|
||||
return typeElement != null && typeElement == _forbiddenClass;
|
||||
}
|
||||
|
||||
bool _isReflectionCapabilitiesImport(ImportDirective node) {
|
||||
return node.uriElement == _forbiddenClass.library;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitImportDirective(ImportDirective node) {
|
||||
if (_isReflectionCapabilitiesImport(node)) {
|
||||
// TODO(kegluneq): Remove newlines once dart_style bug is fixed.
|
||||
// https://github.com/dart-lang/dart_style/issues/178
|
||||
// _writer.print('\n/* ReflectionCapabilities import removed */\n');
|
||||
_writer.print(_codegen.codegenImport());
|
||||
// TODO(kegluneq): Remove once we generate all needed code.
|
||||
{
|
||||
super.visitImportDirective(node);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return super.visitImportDirective(node);
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitAssignmentExpression(AssignmentExpression node) {
|
||||
if (node.rightHandSide is InstanceCreationExpression &&
|
||||
_isNewReflectionCapabilities(node.rightHandSide)) {
|
||||
// TODO(kegluneq): Remove newlines once dart_style bug is fixed.
|
||||
// https://github.com/dart-lang/dart_style/issues/178
|
||||
// _writer.print('/* Creation of ReflectionCapabilities removed */\n');
|
||||
_writer.print(_codegen.codegenSetupReflectionCall());
|
||||
|
||||
// TODO(kegluneq): Remove once we generate all needed code.
|
||||
{
|
||||
_writer.print(';');
|
||||
node.leftHandSide.accept(this);
|
||||
_writer.print(' ${node.operator.lexeme} ');
|
||||
super.visitInstanceCreationExpression(node.rightHandSide);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return super.visitAssignmentExpression(node);
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitInstanceCreationExpression(InstanceCreationExpression node) {
|
||||
if (_isNewReflectionCapabilities(node)) {
|
||||
logger.error('Unexpected format in creation of '
|
||||
'${reflectionCapabilitiesTypeName}');
|
||||
} else {
|
||||
return super.visitInstanceCreationExpression(node);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,140 +0,0 @@
|
|||
library angular2.transform;
|
||||
|
||||
import 'package:barback/barback.dart';
|
||||
import 'package:analyzer/src/generated/element.dart';
|
||||
import 'package:code_transformers/resolver.dart';
|
||||
|
||||
Resolvers createResolvers() {
|
||||
return new Resolvers.fromMock({
|
||||
// The list of types below is derived from:
|
||||
// * types that are used internally by the resolver (see
|
||||
// _initializeFrom in resolver.dart).
|
||||
// TODO(jakemac): Move this into code_transformers so it can be shared.
|
||||
'dart:core': '''
|
||||
library dart.core;
|
||||
class Object {}
|
||||
class Function {}
|
||||
class StackTrace {}
|
||||
class Symbol {}
|
||||
class Type {}
|
||||
|
||||
class String extends Object {}
|
||||
class bool extends Object {}
|
||||
class num extends Object {}
|
||||
class int extends num {}
|
||||
class double extends num {}
|
||||
class DateTime extends Object {}
|
||||
class Null extends Object {}
|
||||
|
||||
class Deprecated extends Object {
|
||||
final String expires;
|
||||
const Deprecated(this.expires);
|
||||
}
|
||||
const Object deprecated = const Deprecated("next release");
|
||||
class _Override { const _Override(); }
|
||||
const Object override = const _Override();
|
||||
class _Proxy { const _Proxy(); }
|
||||
const Object proxy = const _Proxy();
|
||||
|
||||
class List<V> extends Object {}
|
||||
class Map<K, V> extends Object {}
|
||||
''',
|
||||
'dart:html': '''
|
||||
library dart.html;
|
||||
class HtmlElement {}
|
||||
''',
|
||||
});
|
||||
}
|
||||
|
||||
const bootstrapMethodName = 'bootstrap';
|
||||
const reflectionCapabilitiesTypeName = 'ReflectionCapabilities';
|
||||
|
||||
/// Provides resolved [Elements] for well-known Angular2 symbols.
|
||||
class Angular2Types {
|
||||
static Map<Resolver, Angular2Types> _cache = {};
|
||||
static final _annotationsLibAssetId =
|
||||
new AssetId('angular2', 'lib/src/core/annotations/annotations.dart');
|
||||
static final _applicationLibAssetId =
|
||||
new AssetId('angular2', 'lib/src/core/application.dart');
|
||||
static final _templateLibAssetId =
|
||||
new AssetId('angular2', 'lib/src/core/annotations/view.dart');
|
||||
static final _reflectionCapabilitiesLibAssetId = new AssetId(
|
||||
'angular2', 'lib/src/reflection/reflection_capabilities.dart');
|
||||
|
||||
final Resolver _resolver;
|
||||
FunctionElement _bootstrapMethod;
|
||||
|
||||
Angular2Types._internal(this._resolver);
|
||||
|
||||
factory Angular2Types(Resolver resolver) {
|
||||
return _cache.putIfAbsent(
|
||||
resolver, () => new Angular2Types._internal(resolver));
|
||||
}
|
||||
|
||||
LibraryElement get annotationsLib =>
|
||||
_resolver.getLibrary(_annotationsLibAssetId);
|
||||
|
||||
ClassElement get directiveAnnotation =>
|
||||
_getTypeSafe(annotationsLib, 'Directive');
|
||||
|
||||
ClassElement get componentAnnotation =>
|
||||
_getTypeSafe(annotationsLib, 'Component');
|
||||
|
||||
ClassElement get decoratorAnnotation =>
|
||||
_getTypeSafe(annotationsLib, 'Decorator');
|
||||
|
||||
LibraryElement get templateLib => _resolver.getLibrary(_templateLibAssetId);
|
||||
|
||||
ClassElement get templateAnnotation => _getTypeSafe(templateLib, 'View');
|
||||
|
||||
LibraryElement get reflectionCapabilitiesLib =>
|
||||
_resolver.getLibrary(_reflectionCapabilitiesLibAssetId);
|
||||
|
||||
ClassElement get reflectionCapabilities =>
|
||||
_getTypeSafe(reflectionCapabilitiesLib, reflectionCapabilitiesTypeName);
|
||||
|
||||
LibraryElement get applicationLib =>
|
||||
_resolver.getLibrary(_applicationLibAssetId);
|
||||
|
||||
FunctionElement get bootstrapMethod {
|
||||
if (_bootstrapMethod == null) {
|
||||
_bootstrapMethod = applicationLib.definingCompilationUnit.functions
|
||||
.firstWhere((FunctionElement el) => el.name == bootstrapMethodName,
|
||||
orElse: () => null);
|
||||
}
|
||||
return _bootstrapMethod;
|
||||
}
|
||||
|
||||
/// Gets the type named [name] in library [lib]. Returns `null` if [lib] is
|
||||
/// `null` or [name] cannot be found in [lib].
|
||||
ClassElement _getTypeSafe(LibraryElement lib, String name) {
|
||||
if (lib == null) return null;
|
||||
return lib.getType(name);
|
||||
}
|
||||
|
||||
/// Whether [clazz] is annotated as a [Component].
|
||||
bool isComponent(ClassElement clazz) =>
|
||||
hasAnnotation(clazz, componentAnnotation);
|
||||
}
|
||||
|
||||
/// Whether [type], its superclass, or one of its interfaces matches [target].
|
||||
bool isAnnotationMatch(InterfaceType type, ClassElement target) {
|
||||
if (type == null || type.element == null) return false;
|
||||
if (type.element.type == target.type) return true;
|
||||
if (isAnnotationMatch(type.superclass, target)) return true;
|
||||
for (var interface in type.interfaces) {
|
||||
if (isAnnotationMatch(interface, target)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Determines whether [clazz] has at least one annotation that `is` a
|
||||
/// [metaClazz].
|
||||
bool hasAnnotation(ClassElement clazz, ClassElement metaClazz) {
|
||||
if (clazz == null || metaClazz == null) return false;
|
||||
return clazz.metadata.firstWhere((ElementAnnotation meta) {
|
||||
// TODO(kegluneq): Make this recognize non-ConstructorElement annotations.
|
||||
return meta.element is ConstructorElement &&
|
||||
isAnnotationMatch(meta.element.returnType, metaClazz);
|
||||
}, orElse: () => null) != null;
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
library angular2.transform;
|
||||
|
||||
import 'package:analyzer/src/generated/ast.dart';
|
||||
import 'package:analyzer/src/generated/element.dart';
|
||||
|
||||
import 'annotation_processor.dart';
|
||||
import 'common/logging.dart';
|
||||
import 'resolvers.dart';
|
||||
|
||||
/// Walks through an Angular2 application, finding all classes matching the
|
||||
/// provided [annotationMatcher].
|
||||
class AngularVisibleTraversal {
|
||||
final Angular2Types _types;
|
||||
final _ComponentParsingAstVisitor _visitor;
|
||||
|
||||
AngularVisibleTraversal(this._types, AnnotationMatcher annotationMatcher)
|
||||
: _visitor = new _ComponentParsingAstVisitor(annotationMatcher);
|
||||
|
||||
/// Walks an Angular2 application, starting with the class represented by
|
||||
/// [entryPoint], which must be annotated as an Angular2 [Component].
|
||||
///
|
||||
/// We recursively check the entryPoint's annotations and constructor
|
||||
/// arguments for types which match the provided [annotationMatcher].
|
||||
void traverse(ClassElement entryPoint) {
|
||||
if (!_types.isComponent(entryPoint)) {
|
||||
throw new ArgumentError.value(entryPoint, 'entryPoint',
|
||||
'Provided entryPoint must be annotated as a Component');
|
||||
}
|
||||
entryPoint.node.accept(_visitor);
|
||||
}
|
||||
}
|
||||
|
||||
class _ComponentParsingAstVisitor extends Object
|
||||
with RecursiveAstVisitor<Object> {
|
||||
final Set<ClassElement> _seen = new Set();
|
||||
final AnnotationMatcher _matcher;
|
||||
|
||||
_ComponentParsingAstVisitor(this._matcher);
|
||||
|
||||
@override
|
||||
Object visitClassDeclaration(ClassDeclaration node) {
|
||||
if (node.element != null) {
|
||||
if (_seen.contains(node.element)) return null;
|
||||
_seen.add(node.element);
|
||||
}
|
||||
|
||||
// Process the class itself.
|
||||
node.name.accept(this);
|
||||
|
||||
// Process metadata information, ignoring [FieldDeclaration]s and
|
||||
// [MethodDeclaration]s (see below).
|
||||
node.metadata.forEach((Annotation meta) => meta.accept(this));
|
||||
|
||||
// Process constructor parameters, fields & methods are ignored below.
|
||||
node.members.forEach((m) => m.accept(this));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitFieldDeclaration(FieldDeclaration node) => null;
|
||||
|
||||
@override
|
||||
Object visitMethodDeclaration(MethodDeclaration node) => null;
|
||||
|
||||
@override
|
||||
Object visitAnnotation(Annotation node) {
|
||||
// TODO(kegluneq): Visit only Angular2 annotations & subtypes.
|
||||
return super.visitAnnotation(node);
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitSimpleIdentifier(SimpleIdentifier node) {
|
||||
if (node.bestElement != null) {
|
||||
if (node.bestElement is ClassElement) {
|
||||
var matches = _matcher.processAnnotations(node.bestElement);
|
||||
// If any of these types are matches, recurse on them.
|
||||
matches.forEach((match) => match.node.accept(this));
|
||||
}
|
||||
}
|
||||
return super.visitSimpleIdentifier(node);
|
||||
}
|
||||
}
|
|
@ -2,12 +2,11 @@ library angular2.transform.reflection_remover.ast_tester;
|
|||
|
||||
import 'package:analyzer/src/generated/ast.dart';
|
||||
import 'package:analyzer/src/generated/element.dart';
|
||||
import 'package:angular2/src/transform/common/names.dart';
|
||||
|
||||
/// An object that checks for [ReflectionCapabilities] syntactically, that is,
|
||||
/// without resolution information.
|
||||
class AstTester {
|
||||
static const REFLECTION_CAPABILITIES_NAME = 'ReflectionCapabilities';
|
||||
|
||||
const AstTester();
|
||||
|
||||
bool isNewReflectionCapabilities(InstanceCreationExpression node) =>
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
library angular2.transform.reflection_remover.codegen;
|
||||
|
||||
import 'package:analyzer/src/generated/ast.dart';
|
||||
import 'package:barback/barback.dart';
|
||||
import 'package:code_transformers/resolver.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'package:angular2/src/transform/common/names.dart';
|
||||
|
@ -23,20 +21,6 @@ class Codegen {
|
|||
if (this.prefix.isEmpty) throw new ArgumentError.value('(empty)', 'prefix');
|
||||
}
|
||||
|
||||
factory Codegen.fromResolver(
|
||||
Resolver resolver, AssetId reflectionEntryPoint, AssetId newEntryPoint) {
|
||||
var lib = resolver.getLibrary(reflectionEntryPoint);
|
||||
var prefix = _PREFIX_BASE;
|
||||
var idx = 0;
|
||||
while (lib.imports.any((import) {
|
||||
return import.prefix != null && import.prefix == prefix;
|
||||
})) {
|
||||
prefix = '${_PREFIX_BASE}${idx++}';
|
||||
}
|
||||
|
||||
return new Codegen(reflectionEntryPoint, newEntryPoint, prefix: prefix);
|
||||
}
|
||||
|
||||
/// Generates code to import the library containing the method which sets up
|
||||
/// Angular2 reflection statically.
|
||||
///
|
||||
|
|
|
@ -2,6 +2,7 @@ library angular2.transform.reflection_remover.rewriter;
|
|||
|
||||
import 'package:analyzer/src/generated/ast.dart';
|
||||
import 'package:angular2/src/transform/common/logging.dart';
|
||||
import 'package:angular2/src/transform/common/names.dart';
|
||||
|
||||
import 'ast_tester.dart';
|
||||
import 'codegen.dart';
|
||||
|
@ -27,12 +28,11 @@ class Rewriter {
|
|||
var visitor = new _FindReflectionCapabilitiesVisitor(_tester);
|
||||
node.accept(visitor);
|
||||
if (visitor.reflectionCapabilityImports.isEmpty) {
|
||||
logger.error(
|
||||
'Failed to find ${AstTester.REFLECTION_CAPABILITIES_NAME} import.');
|
||||
logger.error('Failed to find ${REFLECTION_CAPABILITIES_NAME} import.');
|
||||
return _code;
|
||||
}
|
||||
if (visitor.reflectionCapabilityAssignments.isEmpty) {
|
||||
logger.error('Failed to find ${AstTester.REFLECTION_CAPABILITIES_NAME} '
|
||||
logger.error('Failed to find ${REFLECTION_CAPABILITIES_NAME} '
|
||||
'instantiation.');
|
||||
return _code;
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ class _FindReflectionCapabilitiesVisitor extends Object
|
|||
if (_tester.isNewReflectionCapabilities(node) &&
|
||||
!reflectionCapabilityAssignments.contains(node.parent)) {
|
||||
logger.error('Unexpected format in creation of '
|
||||
'${reflectionCapabilitiesTypeName}');
|
||||
'${REFLECTION_CAPABILITIES_NAME}');
|
||||
}
|
||||
return super.visitInstanceCreationExpression(node);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import 'bind_generator/transformer.dart';
|
|||
import 'reflection_remover/transformer.dart';
|
||||
import 'template_compiler/transformer.dart';
|
||||
import 'common/formatter.dart' as formatter;
|
||||
import 'common/names.dart';
|
||||
import 'common/options.dart';
|
||||
import 'common/options_reader.dart';
|
||||
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
library angular2.test.transform.bind_generator.all_tests;
|
||||
|
||||
import 'dart:io';
|
||||
import 'package:barback/barback.dart';
|
||||
import 'package:angular2/src/transform/bind_generator/generator.dart';
|
||||
import 'package:angular2/src/transform/common/formatter.dart';
|
||||
import 'package:code_transformers/tests.dart';
|
||||
import 'package:dart_style/dart_style.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:guinness/guinness.dart';
|
||||
import 'package:unittest/vm_config.dart';
|
||||
|
||||
import '../common/read_file.dart';
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
library angular2.test.transform.common.read_file;
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:angular2/src/transform/common/asset_reader.dart';
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
library angular2.test.transform.directive_linker.all_tests;
|
||||
|
||||
import 'package:barback/barback.dart';
|
||||
import 'package:angular2/src/transform/common/logging.dart' hide init;
|
||||
import 'package:angular2/src/transform/common/formatter.dart' hide init;
|
||||
import 'package:angular2/src/transform/directive_linker/linker.dart';
|
||||
import 'package:code_transformers/tests.dart';
|
||||
import 'package:dart_style/dart_style.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:guinness/guinness.dart';
|
||||
import 'package:unittest/vm_config.dart';
|
||||
|
||||
import '../common/read_file.dart';
|
||||
|
||||
|
|
|
@ -1,14 +1,8 @@
|
|||
library angular2.test.transform.directive_processor.all_tests;
|
||||
|
||||
import 'dart:io';
|
||||
import 'package:barback/barback.dart';
|
||||
import 'package:angular2/src/transform/directive_processor/rewriter.dart';
|
||||
import 'package:angular2/src/transform/common/formatter.dart';
|
||||
import 'package:code_transformers/tests.dart';
|
||||
import 'package:dart_style/dart_style.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:guinness/guinness.dart';
|
||||
import 'package:unittest/vm_config.dart';
|
||||
|
||||
import '../common/read_file.dart';
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
library angular2.test.transform.integration;
|
||||
|
||||
import 'dart:io';
|
||||
import 'package:angular2/src/dom/html_adapter.dart';
|
||||
import 'package:angular2/src/transform/common/names.dart';
|
||||
import 'package:angular2/transformer.dart';
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
library angular2.test.transform.directive_processor.all_tests;
|
||||
library angular2.test.transform.template_compiler.all_tests;
|
||||
|
||||
import 'package:barback/barback.dart';
|
||||
import 'package:angular2/src/dom/html_adapter.dart';
|
||||
import 'package:angular2/src/transform/common/asset_reader.dart';
|
||||
import 'package:angular2/src/transform/common/logging.dart';
|
||||
import 'package:angular2/src/transform/common/formatter.dart';
|
||||
import 'package:angular2/src/transform/template_compiler/generator.dart';
|
||||
import 'package:dart_style/dart_style.dart';
|
||||
import 'package:guinness/guinness.dart';
|
||||
|
|
Loading…
Reference in New Issue