Chromium Code Reviews| 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 |