| OLD | NEW |
| (Empty) | |
| 1 library angular.template_cache_generator; |
| 2 |
| 3 import 'dart:io'; |
| 4 import 'dart:async'; |
| 5 import 'dart:collection'; |
| 6 |
| 7 import 'package:analyzer/src/generated/ast.dart'; |
| 8 import 'source_crawler_impl.dart'; |
| 9 |
| 10 const String PACKAGE_PREFIX = 'package:'; |
| 11 const String DART_PACKAGE_PREFIX = 'dart:'; |
| 12 |
| 13 String fileHeader(String library) => '''// GENERATED, DO NOT EDIT! |
| 14 library ${library}; |
| 15 |
| 16 import 'package:angular/angular.dart'; |
| 17 |
| 18 primeTemplateCache(TemplateCache tc) { |
| 19 '''; |
| 20 |
| 21 const String FILE_FOOTER = '}'; |
| 22 const SYSTEM_PACKAGE_ROOT = '%SYSTEM_PACKAGE_ROOT%'; |
| 23 |
| 24 main(args) { |
| 25 if (args.length < 4) { |
| 26 print('Usage: templace_cache_generator path_to_entry_point output ' |
| 27 'package_root1,package_root2,...|$SYSTEM_PACKAGE_ROOT ' |
| 28 'patternUrl1,rewriteTo1;patternUrl2,rewriteTo2 ' |
| 29 'blacklistClass1,blacklistClass2'); |
| 30 exit(1); |
| 31 } |
| 32 |
| 33 var entryPoint = args[0]; |
| 34 var output = args[1]; |
| 35 var outputLibrary = args[2]; |
| 36 var packageRoots = args[3] == SYSTEM_PACKAGE_ROOT ? |
| 37 [Platform.packageRoot] : args[3].split(','); |
| 38 Map<RegExp, String> urlRewriters = parseUrlRemapping(args[4]); |
| 39 Set<String> blacklistedClasses = (args.length > 5) |
| 40 ? new Set.from(args[5].split(',')) |
| 41 : new Set(); |
| 42 |
| 43 print('entryPoint: $entryPoint'); |
| 44 print('output: $output'); |
| 45 print('outputLibrary: $outputLibrary'); |
| 46 print('packageRoots: $packageRoots'); |
| 47 print('url rewritters: ' + args[4]); |
| 48 print('blacklistedClasses: ' + blacklistedClasses.join(', ')); |
| 49 |
| 50 |
| 51 Map<String, String> templates = {}; |
| 52 |
| 53 var c = new SourceCrawlerImpl(packageRoots); |
| 54 var visitor = |
| 55 new TemplateCollectingVisitor(templates, blacklistedClasses, c); |
| 56 c.crawl(entryPoint, (CompilationUnit compilationUnit) => |
| 57 visitor(compilationUnit)); |
| 58 |
| 59 var sink = new File(output).openWrite(); |
| 60 return printTemplateCache( |
| 61 templates, urlRewriters, outputLibrary, sink).then((_) { |
| 62 return sink.flush(); |
| 63 }); |
| 64 } |
| 65 |
| 66 Map<RegExp, String> parseUrlRemapping(String argument) { |
| 67 Map<RegExp, String> result = new LinkedHashMap(); |
| 68 if (argument.isEmpty) { |
| 69 return result; |
| 70 } |
| 71 |
| 72 argument.split(";").forEach((String pair) { |
| 73 List<String> remapping = pair.split(","); |
| 74 result[new RegExp(remapping[0])] = remapping[1]; |
| 75 }); |
| 76 return result; |
| 77 } |
| 78 |
| 79 printTemplateCache(Map<String, String> templateKeyMap, |
| 80 Map<RegExp, String> urlRewriters, |
| 81 String outputLibrary, |
| 82 IOSink outSink) { |
| 83 |
| 84 outSink.write(fileHeader(outputLibrary)); |
| 85 |
| 86 List<Future> reads = <Future>[]; |
| 87 templateKeyMap.forEach((uri, templateFile) { |
| 88 reads.add(new File(templateFile).readAsString().then((fileStr) { |
| 89 fileStr = fileStr.replaceAll('"""', r'\"\"\"'); |
| 90 String resultUri = uri; |
| 91 urlRewriters.forEach((regexp, replacement) { |
| 92 resultUri = resultUri.replaceFirst(regexp, replacement); |
| 93 }); |
| 94 outSink.write( |
| 95 'tc.put("$resultUri", new HttpResponse(200, r"""$fileStr"""));\n'); |
| 96 })); |
| 97 }); |
| 98 |
| 99 // Wait until all templates files are processed. |
| 100 return Future.wait(reads).then((_) { |
| 101 outSink.write(FILE_FOOTER); |
| 102 }); |
| 103 } |
| 104 |
| 105 class TemplateCollectingVisitor { |
| 106 Map<String, String> templates; |
| 107 Set<String> blacklistedClasses; |
| 108 SourceCrawlerImpl sourceCrawlerImpl; |
| 109 |
| 110 TemplateCollectingVisitor(this.templates, this.blacklistedClasses, |
| 111 this.sourceCrawlerImpl); |
| 112 |
| 113 call(CompilationUnit cu) { |
| 114 cu.declarations.forEach((CompilationUnitMember declaration) { |
| 115 // We only care about classes. |
| 116 if (declaration is! ClassDeclaration) return; |
| 117 ClassDeclaration clazz = declaration; |
| 118 List<String> cacheUris = []; |
| 119 bool cache = true; |
| 120 clazz.metadata.forEach((Annotation ann) { |
| 121 if (ann.arguments == null) return; // Ignore non-class annotations. |
| 122 // TODO(tsander): Add library name as class name could conflict. |
| 123 if (blacklistedClasses.contains(clazz.name.name)) return; |
| 124 |
| 125 switch (ann.name.name) { |
| 126 case 'NgComponent': |
| 127 extractNgComponentMetadata(ann, cacheUris); break; |
| 128 case 'NgTemplateCache': |
| 129 cache = extractNgTemplateCache(ann, cacheUris); break; |
| 130 } |
| 131 }); |
| 132 if (cache && cacheUris.isNotEmpty) { |
| 133 cacheUris.forEach((uri) => storeUriAsset(uri)); |
| 134 } |
| 135 }); |
| 136 } |
| 137 |
| 138 void extractNgComponentMetadata(Annotation ann, List<String> cacheUris) { |
| 139 ann.arguments.arguments.forEach((Expression arg) { |
| 140 if (arg is NamedExpression) { |
| 141 NamedExpression namedArg = arg; |
| 142 var paramName = namedArg.name.label.name; |
| 143 if (paramName == 'templateUrl' || paramName == 'cssUrl') { |
| 144 cacheUris.add(assertString(namedArg.expression).stringValue); |
| 145 } |
| 146 } |
| 147 }); |
| 148 } |
| 149 |
| 150 bool extractNgTemplateCache( |
| 151 Annotation ann, List<String> cacheUris) { |
| 152 bool cache = true; |
| 153 ann.arguments.arguments.forEach((Expression arg) { |
| 154 if (arg is NamedExpression) { |
| 155 NamedExpression namedArg = arg; |
| 156 var paramName = namedArg.name.label.name; |
| 157 if (paramName == 'preCacheUrls') { |
| 158 assertList(namedArg.expression).elements |
| 159 .forEach((expression) => |
| 160 cacheUris.add(assertString(expression).stringValue)); |
| 161 } |
| 162 if (paramName == 'cache') { |
| 163 cache = assertBoolean(namedArg.expression).value; |
| 164 } |
| 165 } |
| 166 }); |
| 167 return cache; |
| 168 } |
| 169 |
| 170 void storeUriAsset(String uri) { |
| 171 String assetFileLocation = |
| 172 uri.startsWith('package:') ? |
| 173 sourceCrawlerImpl.resolvePackagePath(uri) : uri; |
| 174 if (assetFileLocation == null) { |
| 175 print("Could not find asset for uri: $uri"); |
| 176 } else { |
| 177 templates[uri] = assetFileLocation; |
| 178 } |
| 179 } |
| 180 |
| 181 BooleanLiteral assertBoolean(Expression key) { |
| 182 if (key is! BooleanLiteral) { |
| 183 throw 'must be a boolean literal: ${key.runtimeType}'; |
| 184 } |
| 185 return key; |
| 186 } |
| 187 |
| 188 ListLiteral assertList(Expression key) { |
| 189 if (key is! ListLiteral) { |
| 190 throw 'must be a list literal: ${key.runtimeType}'; |
| 191 } |
| 192 return key; |
| 193 } |
| 194 |
| 195 StringLiteral assertString(Expression key) { |
| 196 if (key is! StringLiteral) { |
| 197 throw 'must be a string literal: ${key.runtimeType}'; |
| 198 } |
| 199 return key; |
| 200 } |
| 201 } |
| OLD | NEW |