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 /** Transfomer that combines multiple dart script tags into a single one. */ | 5 /// Transfomer that combines multiple dart script tags into a single one. |
6 library polymer.src.build.script_compactor; | 6 library polymer.src.build.script_compactor; |
7 | 7 |
8 import 'dart:async'; | 8 import 'dart:async'; |
9 import 'dart:convert'; | 9 import 'dart:convert'; |
10 | 10 |
11 import 'package:analyzer/src/generated/ast.dart'; | 11 import 'package:analyzer/src/generated/ast.dart'; |
12 import 'package:analyzer/src/generated/error.dart'; | 12 import 'package:analyzer/src/generated/error.dart'; |
13 import 'package:analyzer/src/generated/parser.dart'; | 13 import 'package:analyzer/src/generated/parser.dart'; |
14 import 'package:analyzer/src/generated/scanner.dart'; | 14 import 'package:analyzer/src/generated/scanner.dart'; |
15 import 'package:barback/barback.dart'; | 15 import 'package:barback/barback.dart'; |
16 import 'package:path/path.dart' as path; | 16 import 'package:path/path.dart' as path; |
17 import 'package:source_maps/span.dart' show SourceFile; | 17 import 'package:source_maps/span.dart' show SourceFile; |
18 | 18 |
19 import 'code_extractor.dart'; // import just for documentation. | 19 import 'code_extractor.dart'; // import just for documentation. |
20 import 'common.dart'; | 20 import 'common.dart'; |
21 | 21 |
22 /** | 22 /// Combines Dart script tags into a single script tag, and creates a new Dart |
23 * Combines Dart script tags into a single script tag, and creates a new Dart | 23 /// file that calls the main function of each of the original script tags. |
24 * file that calls the main function of each of the original script tags. | 24 /// |
25 * | 25 /// This transformer assumes that all script tags point to external files. To |
26 * This transformer assumes that all script tags point to external files. To | 26 /// support script tags with inlined code, use this transformer after running |
27 * support script tags with inlined code, use this transformer after running | 27 /// [InlineCodeExtractor] on an earlier phase. |
28 * [InlineCodeExtractor] on an earlier phase. | 28 /// |
29 * | 29 /// Internally, this transformer will convert each script tag into an import |
30 * Internally, this transformer will convert each script tag into an import | 30 /// statement to a library, and then uses `initPolymer` (see polymer.dart) to |
31 * statement to a library, and then uses `initPolymer` (see polymer.dart) to | 31 /// process `@initMethod` and `@CustomTag` annotations in those libraries. |
32 * process `@initMethod` and `@CustomTag` annotations in those libraries. | |
33 */ | |
34 class ScriptCompactor extends Transformer with PolymerTransformer { | 32 class ScriptCompactor extends Transformer with PolymerTransformer { |
35 final TransformOptions options; | 33 final TransformOptions options; |
36 | 34 |
37 ScriptCompactor(this.options); | 35 ScriptCompactor(this.options); |
38 | 36 |
39 /** Only run on entry point .html files. */ | 37 /// Only run on entry point .html files. |
40 Future<bool> isPrimary(Asset input) => | 38 Future<bool> isPrimary(Asset input) => |
41 new Future.value(options.isHtmlEntryPoint(input.id)); | 39 new Future.value(options.isHtmlEntryPoint(input.id)); |
42 | 40 |
43 Future apply(Transform transform) { | 41 Future apply(Transform transform) { |
44 var id = transform.primaryInput.id; | 42 var id = transform.primaryInput.id; |
45 var secondaryId = id.addExtension('.scriptUrls'); | 43 var secondaryId = id.addExtension('.scriptUrls'); |
46 var logger = transform.logger; | 44 var logger = transform.logger; |
47 return readPrimaryAsHtml(transform).then((document) { | 45 return readPrimaryAsHtml(transform).then((document) { |
48 return transform.readInputAsString(secondaryId).then((libraryIds) { | 46 return transform.readInputAsString(secondaryId).then((libraryIds) { |
49 var libraries = (JSON.decode(libraryIds) as Iterable).map( | 47 var libraries = (JSON.decode(libraryIds) as Iterable).map( |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
116 ..writeln('}'); | 114 ..writeln('}'); |
117 | 115 |
118 transform.addOutput(new Asset.fromString( | 116 transform.addOutput(new Asset.fromString( |
119 bootstrapId, buffer.toString())); | 117 bootstrapId, buffer.toString())); |
120 transform.addOutput(new Asset.fromString(id, document.outerHtml)); | 118 transform.addOutput(new Asset.fromString(id, document.outerHtml)); |
121 }); | 119 }); |
122 }); | 120 }); |
123 }); | 121 }); |
124 } | 122 } |
125 | 123 |
126 /** | 124 /// Computes the initializers of [dartLibrary]. That is, a closure that calls |
127 * Computes the initializers of [dartLibrary]. That is, a closure that calls | 125 /// Polymer.register for each @CustomTag, and any public top-level methods |
128 * Polymer.register for each @CustomTag, and any public top-level methods | 126 /// labeled with @initMethod. |
129 * labeled with @initMethod. | |
130 */ | |
131 Future<List<_Initializer>> _initializersOf( | 127 Future<List<_Initializer>> _initializersOf( |
132 AssetId dartLibrary, Transform transform, TransformLogger logger) { | 128 AssetId dartLibrary, Transform transform, TransformLogger logger) { |
133 var initializers = []; | 129 var initializers = []; |
134 return transform.readInputAsString(dartLibrary).then((code) { | 130 return transform.readInputAsString(dartLibrary).then((code) { |
135 var file = new SourceFile.text(_simpleUriForSource(dartLibrary), code); | 131 var file = new SourceFile.text(_simpleUriForSource(dartLibrary), code); |
136 var unit = _parseCompilationUnit(code); | 132 var unit = _parseCompilationUnit(code); |
137 | 133 |
138 return Future.forEach(unit.directives, (directive) { | 134 return Future.forEach(unit.directives, (directive) { |
139 // Include anything from parts. | 135 // Include anything from parts. |
140 if (directive is PartDirective) { | 136 if (directive is PartDirective) { |
(...skipping 23 matching lines...) Expand all Loading... | |
164 } | 160 } |
165 return initializers; | 161 return initializers; |
166 }); | 162 }); |
167 }); | 163 }); |
168 } | 164 } |
169 | 165 |
170 static String _simpleUriForSource(AssetId source) => | 166 static String _simpleUriForSource(AssetId source) => |
171 source.path.startsWith('lib/') | 167 source.path.startsWith('lib/') |
172 ? 'package:${source.package}/${source.path.substring(4)}' : source.path; | 168 ? 'package:${source.package}/${source.path.substring(4)}' : source.path; |
173 | 169 |
174 /** | 170 /// Filter [exportedInitializers] according to [directive]'s show/hide |
175 * Filter [exportedInitializers] according to [directive]'s show/hide | 171 /// combinators and add the result to [initializers]. |
176 * combinators and add the result to [initializers]. | |
177 */ | |
178 // TODO(sigmund): call the analyzer's resolver instead? | 172 // TODO(sigmund): call the analyzer's resolver instead? |
179 static _processExportDirective(ExportDirective directive, | 173 static _processExportDirective(ExportDirective directive, |
180 List<_Initializer> exportedInitializers, | 174 List<_Initializer> exportedInitializers, |
181 List<_Initializer> initializers) { | 175 List<_Initializer> initializers) { |
182 for (var combinator in directive.combinators) { | 176 for (var combinator in directive.combinators) { |
183 if (combinator is ShowCombinator) { | 177 if (combinator is ShowCombinator) { |
184 var show = combinator.shownNames.map((n) => n.name).toSet(); | 178 var show = combinator.shownNames.map((n) => n.name).toSet(); |
185 exportedInitializers.retainWhere((e) => show.contains(e.symbolName)); | 179 exportedInitializers.retainWhere((e) => show.contains(e.symbolName)); |
186 } else if (combinator is HideCombinator) { | 180 } else if (combinator is HideCombinator) { |
187 var hide = combinator.hiddenNames.map((n) => n.name).toSet(); | 181 var hide = combinator.hiddenNames.map((n) => n.name).toSet(); |
188 exportedInitializers.removeWhere((e) => hide.contains(e.symbolName)); | 182 exportedInitializers.removeWhere((e) => hide.contains(e.symbolName)); |
189 } | 183 } |
190 } | 184 } |
191 initializers.addAll(exportedInitializers); | 185 initializers.addAll(exportedInitializers); |
192 } | 186 } |
193 | 187 |
194 /** | 188 /// Add an initializer to register [node] as a polymer element if it contains |
195 * Add an initializer to register [node] as a polymer element if it contains | 189 /// an appropriate [CustomTag] annotation. |
196 * an appropriate [CustomTag] annotation. | |
197 */ | |
198 static _processClassDeclaration(ClassDeclaration node, | 190 static _processClassDeclaration(ClassDeclaration node, |
199 List<_Initializer> initializers, SourceFile file, | 191 List<_Initializer> initializers, SourceFile file, |
200 TransformLogger logger) { | 192 TransformLogger logger) { |
201 for (var meta in node.metadata) { | 193 for (var meta in node.metadata) { |
202 if (!_isCustomTagAnnotation(meta)) continue; | 194 if (!_isCustomTagAnnotation(meta)) continue; |
203 var args = meta.arguments.arguments; | 195 var args = meta.arguments.arguments; |
204 if (args == null || args.length == 0) { | 196 if (args == null || args.length == 0) { |
205 logger.error('Missing argument in @CustomTag annotation', | 197 logger.error('Missing argument in @CustomTag annotation', |
206 span: _getSpan(file, meta)); | 198 span: _getSpan(file, meta)); |
207 continue; | 199 continue; |
208 } | 200 } |
209 | 201 |
210 var tagName = args[0].stringValue; | 202 var tagName = args[0].stringValue; |
211 var typeName = node.name.name; | 203 var typeName = node.name.name; |
212 if (typeName.startsWith('_')) { | 204 if (typeName.startsWith('_')) { |
213 logger.error('@CustomTag is no longer supported on private ' | 205 logger.error('@CustomTag is no longer supported on private ' |
214 'classes: $tagName', span: _getSpan(file, node.name)); | 206 'classes: $tagName', span: _getSpan(file, node.name)); |
215 continue; | 207 continue; |
216 } | 208 } |
217 initializers.add(new _CustomTagInitializer(tagName, typeName)); | 209 initializers.add(new _CustomTagInitializer(tagName, typeName)); |
218 } | 210 } |
219 } | 211 } |
220 | 212 |
221 /** a method initializer for [function]. */ | 213 /// a method initializer for [function]. |
Siggi Cherem (dart-lang)
2014/02/25 23:32:45
if you don't mind fixing - seems like a word was d
Jennifer Messerly
2014/02/25 23:42:42
good catch! done
| |
222 static _processFunctionDeclaration(FunctionDeclaration function, | 214 static _processFunctionDeclaration(FunctionDeclaration function, |
223 List<_Initializer> initializers, SourceFile file, | 215 List<_Initializer> initializers, SourceFile file, |
224 TransformLogger logger) { | 216 TransformLogger logger) { |
225 var name = function.name.name; | 217 var name = function.name.name; |
226 if (name.startsWith('_')) { | 218 if (name.startsWith('_')) { |
227 logger.error('@initMethod is no longer supported on private ' | 219 logger.error('@initMethod is no longer supported on private ' |
228 'functions: $name', span: _getSpan(file, function.name)); | 220 'functions: $name', span: _getSpan(file, function.name)); |
229 return; | 221 return; |
230 } | 222 } |
231 initializers.add(new _InitMethodInitializer(name)); | 223 initializers.add(new _InitMethodInitializer(name)); |
232 } | 224 } |
233 } | 225 } |
234 | 226 |
235 /** Parse [code] using analyzer. */ | 227 /// Parse [code] using analyzer. |
236 CompilationUnit _parseCompilationUnit(String code) { | 228 CompilationUnit _parseCompilationUnit(String code) { |
237 var errorListener = new _ErrorCollector(); | 229 var errorListener = new _ErrorCollector(); |
238 var reader = new CharSequenceReader(code); | 230 var reader = new CharSequenceReader(code); |
239 var scanner = new Scanner(null, reader, errorListener); | 231 var scanner = new Scanner(null, reader, errorListener); |
240 var token = scanner.tokenize(); | 232 var token = scanner.tokenize(); |
241 var parser = new Parser(null, errorListener); | 233 var parser = new Parser(null, errorListener); |
242 return parser.parseCompilationUnit(token); | 234 return parser.parseCompilationUnit(token); |
243 } | 235 } |
244 | 236 |
245 class _ErrorCollector extends AnalysisErrorListener { | 237 class _ErrorCollector extends AnalysisErrorListener { |
(...skipping 30 matching lines...) Expand all Loading... | |
276 "() => Polymer.register('$tagName', $prefix.$typeName)"; | 268 "() => Polymer.register('$tagName', $prefix.$typeName)"; |
277 } | 269 } |
278 | 270 |
279 _getSpan(SourceFile file, ASTNode node) => file.span(node.offset, node.end); | 271 _getSpan(SourceFile file, ASTNode node) => file.span(node.offset, node.end); |
280 | 272 |
281 const MAIN_HEADER = """ | 273 const MAIN_HEADER = """ |
282 library app_bootstrap; | 274 library app_bootstrap; |
283 | 275 |
284 import 'package:polymer/polymer.dart'; | 276 import 'package:polymer/polymer.dart'; |
285 """; | 277 """; |
OLD | NEW |