OLD | NEW |
(Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 /// Transfomer used for pub-serve and pub-deploy. |
| 6 library polymer.transformer; |
| 7 |
| 8 import 'package:barback/barback.dart'; |
| 9 import 'package:observe/transformer.dart'; |
| 10 import 'package:path/path.dart' as path; |
| 11 |
| 12 import 'src/build/build_filter.dart'; |
| 13 import 'src/build/common.dart'; |
| 14 import 'src/build/index_page_builder.dart'; |
| 15 import 'src/build/import_inliner.dart'; |
| 16 import 'src/build/linter.dart'; |
| 17 import 'src/build/build_log_combiner.dart'; |
| 18 import 'src/build/polyfill_injector.dart'; |
| 19 import 'src/build/script_compactor.dart'; |
| 20 |
| 21 /// The Polymer transformer, which internally runs several phases that will: |
| 22 /// * Extract inlined script tags into their separate files |
| 23 /// * Apply the observable transformer on every Dart script. |
| 24 /// * Inline imported html files |
| 25 /// * Combine scripts from multiple files into a single script tag |
| 26 /// * Inject extra polyfills needed to run on all browsers. |
| 27 /// |
| 28 /// At the end of these phases, this tranformer produces a single entrypoint |
| 29 /// HTML file with a single Dart script that can later be compiled with dart2js. |
| 30 class PolymerTransformerGroup implements TransformerGroup { |
| 31 final Iterable<Iterable> phases; |
| 32 |
| 33 PolymerTransformerGroup(TransformOptions options) |
| 34 : phases = createDeployPhases(options); |
| 35 |
| 36 PolymerTransformerGroup.asPlugin(BarbackSettings settings) |
| 37 : this(_parseSettings(settings)); |
| 38 } |
| 39 |
| 40 TransformOptions _parseSettings(BarbackSettings settings) { |
| 41 var args = settings.configuration; |
| 42 bool releaseMode = settings.mode == BarbackMode.RELEASE; |
| 43 bool jsOption = args['js']; |
| 44 bool csp = args['csp'] == true; // defaults to false |
| 45 bool injectBuildLogs = |
| 46 !releaseMode && args['inject_build_logs_in_output'] != false; |
| 47 bool injectWebComponentsJs = true; |
| 48 if (args['inject_platform_js'] != null) { |
| 49 print( |
| 50 'Deprecated polymer transformer option `inject_platform_js`. This has ' |
| 51 'been renamed `inject_web_components_js` to match the new file name.'); |
| 52 injectWebComponentsJs = args['inject_platform_js'] != false; |
| 53 } |
| 54 if (args['inject_webcomponents_js'] != null) { |
| 55 injectWebComponentsJs = args['inject_webcomponents_js'] != false; |
| 56 } |
| 57 return new TransformOptions( |
| 58 entryPoints: readFileList(args['entry_points']), |
| 59 inlineStylesheets: _readInlineStylesheets(args['inline_stylesheets']), |
| 60 directlyIncludeJS: jsOption == null ? releaseMode : jsOption, |
| 61 contentSecurityPolicy: csp, |
| 62 releaseMode: releaseMode, |
| 63 lint: _parseLintOption(args['lint']), |
| 64 injectBuildLogsInOutput: injectBuildLogs, |
| 65 injectWebComponentsJs: injectWebComponentsJs); |
| 66 } |
| 67 |
| 68 // Lint option can be empty (all files), false, true, or a map indicating |
| 69 // include/exclude files. |
| 70 _parseLintOption(value) { |
| 71 var lint = null; |
| 72 if (value == null || value == true) return new LintOptions(); |
| 73 if (value == false) return new LintOptions.disabled(); |
| 74 if (value is Map && value.length == 1) { |
| 75 var key = value.keys.single; |
| 76 var files = readFileList(value[key]); |
| 77 if (key == 'include') { |
| 78 return new LintOptions.include(files); |
| 79 } else if (key == 'exclude') { |
| 80 return new LintOptions.exclude(files); |
| 81 } |
| 82 } |
| 83 |
| 84 // Any other case it is an error: |
| 85 print('Invalid value for "lint" in the polymer transformer. ' |
| 86 'Expected one of the following: \n' |
| 87 ' lint: true # or\n' |
| 88 ' lint: false # or\n' |
| 89 ' lint: \n' |
| 90 ' include: \n' |
| 91 ' - file1 \n' |
| 92 ' - file2 # or \n' |
| 93 ' lint: \n' |
| 94 ' exclude: \n' |
| 95 ' - file1 \n' |
| 96 ' - file2 \n'); |
| 97 return new LintOptions(); |
| 98 } |
| 99 |
| 100 readFileList(value) { |
| 101 if (value == null) return null; |
| 102 var files = []; |
| 103 bool error; |
| 104 if (value is List) { |
| 105 files = value; |
| 106 error = value.any((e) => e is! String); |
| 107 } else if (value is String) { |
| 108 files = [value]; |
| 109 error = false; |
| 110 } else { |
| 111 error = true; |
| 112 } |
| 113 if (error) { |
| 114 print('Invalid value for "entry_points" in the polymer transformer.'); |
| 115 } |
| 116 return files; |
| 117 } |
| 118 |
| 119 Map<String, bool> _readInlineStylesheets(settingValue) { |
| 120 if (settingValue == null) return null; |
| 121 var inlineStylesheets = {}; |
| 122 bool error = false; |
| 123 if (settingValue is Map) { |
| 124 settingValue.forEach((key, value) { |
| 125 if (value is! bool || key is! String) { |
| 126 error = true; |
| 127 return; |
| 128 } |
| 129 if (key == 'default') { |
| 130 inlineStylesheets[key] = value; |
| 131 return; |
| 132 }; |
| 133 key = systemToAssetPath(key); |
| 134 // Special case package urls, convert to AssetId and use serialized form. |
| 135 var packageMatch = _PACKAGE_PATH_REGEX.matchAsPrefix(key); |
| 136 if (packageMatch != null) { |
| 137 var package = packageMatch[1]; |
| 138 var path = 'lib/${packageMatch[2]}'; |
| 139 key = new AssetId(package, path).toString(); |
| 140 } |
| 141 inlineStylesheets[key] = value; |
| 142 }); |
| 143 } else if (settingValue is bool) { |
| 144 inlineStylesheets['default'] = settingValue; |
| 145 } else { |
| 146 error = true; |
| 147 } |
| 148 if (error) { |
| 149 print('Invalid value for "inline_stylesheets" in the polymer transformer.'); |
| 150 } |
| 151 return inlineStylesheets; |
| 152 } |
| 153 |
| 154 /// Create deploy phases for Polymer. Note that inlining HTML Imports |
| 155 /// comes first (other than linter, if [options.linter] is enabled), which |
| 156 /// allows the rest of the HTML-processing phases to operate only on HTML that |
| 157 /// is actually imported. |
| 158 List<List<Transformer>> createDeployPhases( |
| 159 TransformOptions options, {String sdkDir}) { |
| 160 // TODO(sigmund): this should be done differently. We should lint everything |
| 161 // that is reachable and have the option to lint the rest (similar to how |
| 162 // dart2js can analyze reachable code or entire libraries). |
| 163 var phases = options.lint.enabled ? [[new Linter(options)]] : []; |
| 164 phases.addAll([ |
| 165 [new ImportInliner(options)], |
| 166 [new ObservableTransformer()], |
| 167 [new ScriptCompactor(options, sdkDir: sdkDir)], |
| 168 [new PolyfillInjector(options)], |
| 169 [new BuildFilter(options)], |
| 170 [new BuildLogCombiner(options)], |
| 171 ]); |
| 172 if (!options.releaseMode) { |
| 173 phases.add([new IndexPageBuilder(options)]); |
| 174 } |
| 175 return phases; |
| 176 } |
| 177 |
| 178 final RegExp _PACKAGE_PATH_REGEX = new RegExp(r'packages\/([^\/]+)\/(.*)'); |
OLD | NEW |