| 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 /// Common methods used by transfomers. | 5 /// Common methods used by transfomers. |
| 6 library polymer.src.build.common; | 6 library polymer.src.build.common; |
| 7 | 7 |
| 8 import 'dart:async'; | 8 import 'dart:async'; |
| 9 | 9 |
| 10 import 'package:analyzer/src/generated/ast.dart'; | 10 import 'package:analyzer/src/generated/ast.dart'; |
| 11 import 'package:analyzer/src/generated/error.dart'; | 11 import 'package:analyzer/src/generated/error.dart'; |
| 12 import 'package:analyzer/src/generated/parser.dart'; | 12 import 'package:analyzer/src/generated/parser.dart'; |
| 13 import 'package:analyzer/src/generated/scanner.dart'; | 13 import 'package:analyzer/src/generated/scanner.dart'; |
| 14 import 'package:barback/barback.dart'; | 14 import 'package:barback/barback.dart'; |
| 15 import 'package:html5lib/dom.dart' show Document; | 15 import 'package:html5lib/dom.dart' show Document; |
| 16 import 'package:html5lib/parser.dart' show HtmlParser; | 16 import 'package:html5lib/parser.dart' show HtmlParser; |
| 17 import 'package:path/path.dart' as path; | 17 import 'package:path/path.dart' as path; |
| 18 import 'package:observe/transformer.dart' show ObservableTransformer; | 18 import 'package:observe/transformer.dart' show ObservableTransformer; |
| 19 import 'package:source_maps/span.dart' show Span; | 19 import 'package:source_maps/span.dart' show Span; |
| 20 | 20 |
| 21 const _ignoredErrors = const [ |
| 22 'unexpected-dash-after-double-dash-in-comment', |
| 23 'unexpected-char-in-comment', |
| 24 ]; |
| 25 |
| 21 /// Parses an HTML file [contents] and returns a DOM-like tree. Adds emitted | 26 /// Parses an HTML file [contents] and returns a DOM-like tree. Adds emitted |
| 22 /// error/warning to [logger]. | 27 /// error/warning to [logger]. |
| 23 Document _parseHtml(String contents, String sourcePath, TransformLogger logger, | 28 Document _parseHtml(String contents, String sourcePath, TransformLogger logger, |
| 24 {bool checkDocType: true}) { | 29 {bool checkDocType: true, bool showWarnings: true}) { |
| 25 // TODO(jmesserly): make HTTP encoding configurable | 30 // TODO(jmesserly): make HTTP encoding configurable |
| 26 var parser = new HtmlParser(contents, encoding: 'utf8', generateSpans: true, | 31 var parser = new HtmlParser(contents, encoding: 'utf8', |
| 27 sourceUrl: sourcePath); | 32 generateSpans: true, sourceUrl: sourcePath); |
| 28 var document = parser.parse(); | 33 var document = parser.parse(); |
| 29 | 34 |
| 30 // Note: errors aren't fatal in HTML (unless strict mode is on). | 35 // Note: errors aren't fatal in HTML (unless strict mode is on). |
| 31 // So just print them as warnings. | 36 // So just print them as warnings. |
| 32 for (var e in parser.errors) { | 37 if (showWarnings) { |
| 33 if (checkDocType || e.errorCode != 'expected-doctype-but-got-start-tag') { | 38 for (var e in parser.errors) { |
| 34 logger.warning(e.message, span: e.span); | 39 if (_ignoredErrors.contains(e.errorCode)) continue; |
| 40 if (checkDocType || e.errorCode != 'expected-doctype-but-got-start-tag') { |
| 41 logger.warning(e.message, span: e.span); |
| 42 } |
| 35 } | 43 } |
| 36 } | 44 } |
| 37 return document; | 45 return document; |
| 38 } | 46 } |
| 39 | 47 |
| 40 /// Additional options used by polymer transformers | 48 /// Additional options used by polymer transformers |
| 41 class TransformOptions { | 49 class TransformOptions { |
| 42 /// List of entrypoints paths. The paths are relative to the package root and | 50 /// List of entrypoints paths. The paths are relative to the package root and |
| 43 /// are represented using posix style, which matches the representation used | 51 /// are represented using posix style, which matches the representation used |
| 44 /// in asset ids in barback. If null, anything under 'web/' or 'test/' is | 52 /// in asset ids in barback. If null, anything under 'web/' or 'test/' is |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 | 100 |
| 93 Future<Document> readPrimaryAsHtml(Transform transform) { | 101 Future<Document> readPrimaryAsHtml(Transform transform) { |
| 94 var asset = transform.primaryInput; | 102 var asset = transform.primaryInput; |
| 95 var id = asset.id; | 103 var id = asset.id; |
| 96 return asset.readAsString().then((content) { | 104 return asset.readAsString().then((content) { |
| 97 return _parseHtml(content, id.path, transform.logger, | 105 return _parseHtml(content, id.path, transform.logger, |
| 98 checkDocType: options.isHtmlEntryPoint(id)); | 106 checkDocType: options.isHtmlEntryPoint(id)); |
| 99 }); | 107 }); |
| 100 } | 108 } |
| 101 | 109 |
| 102 Future<Document> readAsHtml(AssetId id, Transform transform) { | 110 Future<Document> readAsHtml(AssetId id, Transform transform, |
| 111 {bool showWarnings: true}) { |
| 103 var primaryId = transform.primaryInput.id; | 112 var primaryId = transform.primaryInput.id; |
| 104 bool samePackage = id.package == primaryId.package; | 113 bool samePackage = id.package == primaryId.package; |
| 105 var url = spanUrlFor(id, transform); | 114 var url = spanUrlFor(id, transform); |
| 106 return transform.readInputAsString(id).then((content) { | 115 return transform.readInputAsString(id).then((content) { |
| 107 return _parseHtml(content, url, transform.logger, | 116 return _parseHtml(content, url, transform.logger, |
| 108 checkDocType: samePackage && options.isHtmlEntryPoint(id)); | 117 checkDocType: samePackage && options.isHtmlEntryPoint(id), |
| 118 showWarnings: showWarnings); |
| 109 }); | 119 }); |
| 110 } | 120 } |
| 111 | 121 |
| 112 Future<bool> assetExists(AssetId id, Transform transform) => | 122 Future<bool> assetExists(AssetId id, Transform transform) => |
| 113 transform.getInput(id).then((_) => true).catchError((_) => false); | 123 transform.getInput(id).then((_) => true).catchError((_) => false); |
| 114 | 124 |
| 115 String toString() => 'polymer ($runtimeType)'; | 125 String toString() => 'polymer ($runtimeType)'; |
| 116 } | 126 } |
| 117 | 127 |
| 118 /// Gets the appropriate URL to use in a [Span] to produce messages | 128 /// Gets the appropriate URL to use in a [Span] to produce messages |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 from: builder.join('/', builder.dirname(sourceId.path))); | 175 from: builder.join('/', builder.dirname(sourceId.path))); |
| 166 } | 176 } |
| 167 | 177 |
| 168 | 178 |
| 169 /// Convert system paths to asset paths (asset paths are posix style). | 179 /// Convert system paths to asset paths (asset paths are posix style). |
| 170 String _systemToAssetPath(String assetPath) { | 180 String _systemToAssetPath(String assetPath) { |
| 171 if (path.Style.platform != path.Style.windows) return assetPath; | 181 if (path.Style.platform != path.Style.windows) return assetPath; |
| 172 return path.posix.joinAll(path.split(assetPath)); | 182 return path.posix.joinAll(path.split(assetPath)); |
| 173 } | 183 } |
| 174 | 184 |
| 175 | |
| 176 /// Parse [code] using analyzer. | |
| 177 CompilationUnit parseCompilationUnit(String code) { | |
| 178 var errorListener = new _ErrorCollector(); | |
| 179 var reader = new CharSequenceReader(code); | |
| 180 var scanner = new Scanner(null, reader, errorListener); | |
| 181 var token = scanner.tokenize(); | |
| 182 var parser = new Parser(null, errorListener); | |
| 183 return parser.parseCompilationUnit(token); | |
| 184 } | |
| 185 | |
| 186 class _ErrorCollector extends AnalysisErrorListener { | |
| 187 final errors = <AnalysisError>[]; | |
| 188 onError(error) => errors.add(error); | |
| 189 } | |
| 190 | |
| 191 /// These names have meaning in SVG or MathML, so they aren't allowed as custom | 185 /// These names have meaning in SVG or MathML, so they aren't allowed as custom |
| 192 /// tags. See [isCustomTagName]. | 186 /// tags. See [isCustomTagName]. |
| 193 const invalidTagNames = const { | 187 const invalidTagNames = const { |
| 194 'annotation-xml': '', | 188 'annotation-xml': '', |
| 195 'color-profile': '', | 189 'color-profile': '', |
| 196 'font-face': '', | 190 'font-face': '', |
| 197 'font-face-src': '', | 191 'font-face-src': '', |
| 198 'font-face-uri': '', | 192 'font-face-uri': '', |
| 199 'font-face-format': '', | 193 'font-face-format': '', |
| 200 'font-face-name': '', | 194 'font-face-name': '', |
| 201 'missing-glyph': '', | 195 'missing-glyph': '', |
| 202 }; | 196 }; |
| 203 | 197 |
| 204 /// Returns true if this is a valid custom element name. See: | 198 /// Returns true if this is a valid custom element name. See: |
| 205 /// <http://w3c.github.io/webcomponents/spec/custom/#dfn-custom-element-type> | 199 /// <http://w3c.github.io/webcomponents/spec/custom/#dfn-custom-element-type> |
| 206 bool isCustomTagName(String name) { | 200 bool isCustomTagName(String name) { |
| 207 if (name == null || !name.contains('-')) return false; | 201 if (name == null || !name.contains('-')) return false; |
| 208 return !invalidTagNames.containsKey(name); | 202 return !invalidTagNames.containsKey(name); |
| 209 } | 203 } |
| 210 | 204 |
| 211 /// Regex to split names in the 'attributes' attribute, which supports 'a b c', | 205 /// Regex to split names in the 'attributes' attribute, which supports 'a b c', |
| 212 /// 'a,b,c', or even 'a b,c'. This is the same as in `lib/src/declaration.dart`. | 206 /// 'a,b,c', or even 'a b,c'. This is the same as in `lib/src/declaration.dart`. |
| 213 final ATTRIBUTES_REGEX = new RegExp(r'\s|,'); | 207 final ATTRIBUTES_REGEX = new RegExp(r'\s|,'); |
| 214 | 208 |
| 215 const POLYMER_EXPERIMENTAL_HTML = 'packages/polymer/polymer_experimental.html'; | 209 const POLYMER_EXPERIMENTAL_HTML = 'packages/polymer/polymer_experimental.html'; |
| OLD | NEW |