Index: third_party/pkg/di/lib/generator.dart |
diff --git a/third_party/pkg/di/lib/generator.dart b/third_party/pkg/di/lib/generator.dart |
index 1266b432d76dddc2627728356affca012c2035c6..7ebb1a9c56ff5e8d5bf870ad9474b0a9108748b4 100644 |
--- a/third_party/pkg/di/lib/generator.dart |
+++ b/third_party/pkg/di/lib/generator.dart |
@@ -7,13 +7,16 @@ import 'package:analyzer/src/generated/sdk.dart' show DartSdk; |
import 'package:analyzer/src/generated/sdk_io.dart' show DirectoryBasedDartSdk; |
import 'package:analyzer/src/generated/element.dart'; |
import 'package:analyzer/src/generated/engine.dart'; |
+import 'package:path/path.dart' as path; |
import 'dart:io'; |
const String PACKAGE_PREFIX = 'package:'; |
const String DART_PACKAGE_PREFIX = 'dart:'; |
+const List<String> _DEFAULT_INJECTABLE_ANNOTATIONS = |
+ const ['di.annotations.Injectable']; |
-main(args) { |
+main(List<String> args) { |
if (args.length < 4) { |
print('Usage: generator path_to_sdk file_to_resolve annotations output [package_roots+]'); |
exit(0); |
@@ -21,7 +24,8 @@ main(args) { |
var pathToSdk = args[0]; |
var entryPoint = args[1]; |
- var classAnnotations = args[2].split(','); |
+ var classAnnotations = args[2].split(',') |
+ ..addAll(_DEFAULT_INJECTABLE_ANNOTATIONS); |
var output = args[3]; |
var packageRoots = (args.length < 5) ? [Platform.packageRoot] : args.sublist(4); |
@@ -31,7 +35,7 @@ main(args) { |
print('output: $output'); |
print('packageRoots: $packageRoots'); |
- var code = generateCode(entryPoint, classAnnotations, pathToSdk, packageRoots); |
+ var code = generateCode(entryPoint, classAnnotations, pathToSdk, packageRoots, output); |
code.forEach((chunk, code) { |
String fileName = output; |
if (chunk.library != null) { |
@@ -43,14 +47,14 @@ main(args) { |
} |
Map<Chunk, String> generateCode(String entryPoint, List<String> classAnnotations, |
- String pathToSdk, List<String> packageRoots) { |
+ String pathToSdk, List<String> packageRoots, String outputFilename) { |
var c = new SourceCrawler(pathToSdk, packageRoots); |
List<String> imports = <String>[]; |
Map<Chunk, List<ClassElement>> typeFactoryTypes = <Chunk, List<ClassElement>>{}; |
Map<String, String> typeToImport = new Map<String, String>(); |
c.crawl(entryPoint, (CompilationUnitElement compilationUnit, SourceFile source) { |
new CompilationUnitVisitor(c.context, source, classAnnotations, imports, |
- typeToImport, typeFactoryTypes).visit(compilationUnit, source); |
+ typeToImport, typeFactoryTypes, outputFilename).visit(compilationUnit, source); |
}); |
return printLibraryCode(typeToImport, imports, typeFactoryTypes); |
} |
@@ -69,30 +73,43 @@ Map<Chunk, String> printLibraryCode(Map<String, String> typeToImport, |
if (!requiredImports.contains(import)) { |
requiredImports.add(import); |
} |
- return 'import_${imports.indexOf(import)}.${type.name}'; |
+ String prefix = _calculateImportPrefix(import, imports); |
+ return '$prefix.${type.name}'; |
} |
factories[chunk] = new StringBuffer(); |
classes.forEach((ClassElement clazz) { |
StringBuffer factory = new StringBuffer(); |
bool skip = false; |
- factory.write( |
- '${resolveClassIdentifier(clazz.type)}: (f) => '); |
+ factory.write('${resolveClassIdentifier(clazz.type)}: (f) => '); |
factory.write('new ${resolveClassIdentifier(clazz.type)}('); |
ConstructorElement constr = |
clazz.constructors.firstWhere((c) => c.name.isEmpty, |
orElse: () { |
- throw 'Unable to find default constructor for $clazz in ${clazz.source}'; |
+ throw 'Unable to find default constructor for ' |
+ '$clazz in ${clazz.source}'; |
}); |
factory.write(constr.parameters.map((param) { |
if (param.type.element is! ClassElement) { |
throw 'Unable to resolve type for constructor parameter ' |
- '"${param.name}" for type "$clazz" in ${clazz.source}'; |
+ '"${param.name}" for type "$clazz" in ${clazz.source}'; |
} |
if (_isParameterized(param)) { |
- print('WARNING: parameterized types are not supported: $param in $clazz in ${clazz.source}. Skipping!'); |
+ print('WARNING: parameterized types are not supported: ' |
+ '$param in $clazz in ${clazz.source}. Skipping!'); |
skip = true; |
} |
- return 'f(${resolveClassIdentifier(param.type)})'; |
+ var annotations = []; |
+ if (param.metadata.isNotEmpty) { |
+ annotations = param.metadata.map( |
+ (item) => resolveClassIdentifier(item.element.returnType)); |
+ } |
+ StringBuffer output = |
+ new StringBuffer('f(${resolveClassIdentifier(param.type)}'); |
+ if (annotations.isNotEmpty) { |
+ output.write(', ${annotations.first}'); |
+ } |
+ output.write(')'); |
+ return output; |
}).join(', ')); |
factory.write('),\n'); |
if (!skip) { |
@@ -103,7 +120,8 @@ Map<Chunk, String> printLibraryCode(Map<String, String> typeToImport, |
String libSuffix = chunk.library == null ? '' : '.${chunk.library.name}'; |
code.write('library di.generated.type_factories$libSuffix;\n'); |
requiredImports.forEach((import) { |
- code.write ('import "$import" as import_${imports.indexOf(import)};\n'); |
+ String prefix = _calculateImportPrefix(import, imports); |
+ code.write ('import "$import" as $prefix;\n'); |
}); |
code..write('var typeFactories = {\n${factories[chunk]}\n};\n') |
..write('main() {}\n'); |
@@ -113,6 +131,9 @@ Map<Chunk, String> printLibraryCode(Map<String, String> typeToImport, |
return result; |
} |
+String _calculateImportPrefix(String import, List<String> imports) => |
+ 'import_${imports.indexOf(import)}'; |
+ |
_isParameterized(ParameterElement param) { |
String typeName = param.type.toString(); |
@@ -131,12 +152,16 @@ class CompilationUnitVisitor { |
List<String> classAnnotations; |
SourceFile source; |
AnalysisContext context; |
+ String outputFilename; |
CompilationUnitVisitor(this.context, this.source, |
this.classAnnotations, this.imports, this.typeToImport, |
- this.typeFactoryTypes); |
+ this.typeFactoryTypes, this.outputFilename); |
visit(CompilationUnitElement compilationUnit, SourceFile source) { |
+ if (typeFactoryTypes[source.chunk] == null) { |
+ typeFactoryTypes[source.chunk] = <ClassElement>[]; |
+ } |
visitLibrary(compilationUnit.enclosingElement, source); |
List<ClassElement> types = <ClassElement>[]; |
@@ -170,9 +195,6 @@ class CompilationUnitVisitor { |
throw 'Unable to resolve type "$expr" from @Injectables ' |
'in ${library.element.source}'; |
} |
- if (typeFactoryTypes[source.chunk] == null) { |
- typeFactoryTypes[source.chunk] = <ClassElement>[]; |
- } |
if (!typeFactoryTypes[source.chunk].contains(element)) { |
typeFactoryTypes[source.chunk].add(element as ClassElement); |
} |
@@ -188,10 +210,13 @@ class CompilationUnitVisitor { |
if (classElement.name.startsWith('_')) { |
return; // ignore private classes. |
} |
- typeToImport[getCanonicalName(classElement.type)] = |
- source.entryPointImport; |
- if (!imports.contains(source.entryPointImport)) { |
- imports.add(source.entryPointImport); |
+ var importUri = source.entryPointImport; |
+ if (Uri.parse(importUri).scheme == '') { |
+ importUri = path.relative(importUri, from: path.dirname(outputFilename)); |
+ } |
+ typeToImport[getCanonicalName(classElement.type)] = importUri; |
+ if (!imports.contains(importUri)) { |
+ imports.add(importUri); |
} |
for (ElementAnnotation ann in classElement.metadata) { |
if (ann.element is ConstructorElement) { |
@@ -232,13 +257,14 @@ class SourceCrawler { |
SourceCrawler(this.sdkPath, this.packageRoots); |
- void crawl(String entryPoint, CompilationUnitCrawler _visitor) { |
+ void crawl(String entryPoint, CompilationUnitCrawler _visitor, |
+ {bool preserveComments : false}) { |
JavaSystemIO.setProperty("com.google.dart.sdk", sdkPath); |
DartSdk sdk = DirectoryBasedDartSdk.defaultSdk; |
AnalysisOptionsImpl contextOptions = new AnalysisOptionsImpl(); |
contextOptions.cacheSize = 256; |
- contextOptions.preserveComments = false; |
+ contextOptions.preserveComments = preserveComments; |
contextOptions.analyzeFunctionBodies = false; |
context.analysisOptions = contextOptions; |
sdk.context.analysisOptions = contextOptions; |
@@ -246,7 +272,7 @@ class SourceCrawler { |
var packageUriResolver = |
new PackageUriResolver(packageRoots.map( |
(pr) => new JavaFile.fromUri(new Uri.file(pr))).toList()); |
- context.sourceFactory = new SourceFactory.con2([ |
+ context.sourceFactory = new SourceFactory([ |
new DartUriResolver(sdk), |
new FileUriResolver(), |
packageUriResolver |
@@ -256,18 +282,16 @@ class SourceCrawler { |
var entryPointImport; |
if (entryPoint.startsWith(PACKAGE_PREFIX)) { |
entryPointFile = new JavaFile(packageUriResolver |
- .resolveAbsolute(context.sourceFactory.contentCache, |
- Uri.parse(entryPoint)).toString()); |
+ .resolveAbsolute(Uri.parse(entryPoint)).toString()); |
entryPointImport = entryPoint; |
} else { |
entryPointFile = new JavaFile(entryPoint); |
entryPointImport = entryPointFile.getAbsolutePath(); |
} |
- Source source = new FileBasedSource.con1( |
- context.sourceFactory.contentCache, entryPointFile); |
+ Source source = new FileBasedSource.con1(entryPointFile); |
ChangeSet changeSet = new ChangeSet(); |
- changeSet.added(source); |
+ changeSet.addedSource(source); |
context.applyChanges(changeSet); |
LibraryElement rootLib = context.computeLibraryElement(source); |
CompilationUnit resolvedUnit = |