| 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 /** Common methods used by transfomers. */ | |
| 6 library polymer.src.transform.common; | |
| 7 | |
| 8 import 'dart:async'; | |
| 9 | |
| 10 import 'package:barback/barback.dart'; | |
| 11 import 'package:html5lib/dom.dart' show Document; | |
| 12 import 'package:html5lib/parser.dart' show HtmlParser; | |
| 13 import 'package:path/path.dart' as path; | |
| 14 import 'package:source_maps/span.dart' show Span; | |
| 15 | |
| 16 /** | |
| 17 * Parses an HTML file [contents] and returns a DOM-like tree. Adds emitted | |
| 18 * error/warning to [logger]. | |
| 19 */ | |
| 20 Document _parseHtml(String contents, String sourcePath, TransformLogger logger, | |
| 21 {bool checkDocType: true}) { | |
| 22 // TODO(jmesserly): make HTTP encoding configurable | |
| 23 var parser = new HtmlParser(contents, encoding: 'utf8', generateSpans: true, | |
| 24 sourceUrl: sourcePath); | |
| 25 var document = parser.parse(); | |
| 26 | |
| 27 // Note: errors aren't fatal in HTML (unless strict mode is on). | |
| 28 // So just print them as warnings. | |
| 29 for (var e in parser.errors) { | |
| 30 if (checkDocType || e.errorCode != 'expected-doctype-but-got-start-tag') { | |
| 31 logger.warning(e.message, e.span); | |
| 32 } | |
| 33 } | |
| 34 return document; | |
| 35 } | |
| 36 | |
| 37 /** Additional options used by polymer transformers */ | |
| 38 class TransformOptions { | |
| 39 String currentPackage; | |
| 40 List<String> entryPoints; | |
| 41 | |
| 42 TransformOptions([this.currentPackage, entryPoints]) | |
| 43 : entryPoints = entryPoints == null ? null | |
| 44 : entryPoints.map(_systemToAssetPath).toList(); | |
| 45 | |
| 46 /** Whether an asset with [id] is an entry point HTML file. */ | |
| 47 bool isHtmlEntryPoint(AssetId id) { | |
| 48 if (id.extension != '.html') return false; | |
| 49 | |
| 50 // Note: [id.path] is a relative path from the root of a package. | |
| 51 if (currentPackage == null || entryPoints == null) { | |
| 52 return id.path.startsWith('web/') || id.path.startsWith('test/'); | |
| 53 } | |
| 54 | |
| 55 return id.package == currentPackage && entryPoints.contains(id.path); | |
| 56 } | |
| 57 } | |
| 58 | |
| 59 /** Mixin for polymer transformers. */ | |
| 60 abstract class PolymerTransformer { | |
| 61 TransformOptions get options; | |
| 62 | |
| 63 Future<Document> readPrimaryAsHtml(Transform transform) { | |
| 64 var asset = transform.primaryInput; | |
| 65 var id = asset.id; | |
| 66 return asset.readAsString().then((content) { | |
| 67 return _parseHtml(content, id.path, transform.logger, | |
| 68 checkDocType: options.isHtmlEntryPoint(id)); | |
| 69 }); | |
| 70 } | |
| 71 | |
| 72 Future<Document> readAsHtml(AssetId id, Transform transform) { | |
| 73 var primaryId = transform.primaryInput.id; | |
| 74 var url = (id.package == primaryId.package) ? id.path | |
| 75 : assetUrlFor(id, primaryId, transform.logger, allowAssetUrl: true); | |
| 76 return transform.readInputAsString(id).then((content) { | |
| 77 return _parseHtml(content, url, transform.logger, | |
| 78 checkDocType: options.isHtmlEntryPoint(id)); | |
| 79 }); | |
| 80 } | |
| 81 } | |
| 82 | |
| 83 /** Create an [AssetId] for a [url] seen in the [source] asset. */ | |
| 84 // TODO(sigmund): delete once this is part of barback (dartbug.com/12610) | |
| 85 AssetId resolve(AssetId source, String url, TransformLogger logger, Span span) { | |
| 86 if (url == null || url == '') return null; | |
| 87 var uri = Uri.parse(url); | |
| 88 var urlBuilder = path.url; | |
| 89 if (uri.host != '' || uri.scheme != '' || urlBuilder.isAbsolute(url)) { | |
| 90 logger.error('absolute paths not allowed: "$url"', span); | |
| 91 return null; | |
| 92 } | |
| 93 | |
| 94 var package; | |
| 95 var targetPath; | |
| 96 var segments = urlBuilder.split(url); | |
| 97 if (segments[0] == 'packages') { | |
| 98 if (segments.length < 3) { | |
| 99 logger.error("incomplete packages/ path. It should have at least 3 " | |
| 100 "segments packages/name/path-from-name's-lib-dir", span); | |
| 101 return null; | |
| 102 } | |
| 103 package = segments[1]; | |
| 104 targetPath = urlBuilder.join('lib', | |
| 105 urlBuilder.joinAll(segments.sublist(2))); | |
| 106 } else if (segments[0] == 'assets') { | |
| 107 if (segments.length < 3) { | |
| 108 logger.error("incomplete assets/ path. It should have at least 3 " | |
| 109 "segments assets/name/path-from-name's-asset-dir", span); | |
| 110 } | |
| 111 package = segments[1]; | |
| 112 targetPath = urlBuilder.join('asset', | |
| 113 urlBuilder.joinAll(segments.sublist(2))); | |
| 114 } else { | |
| 115 package = source.package; | |
| 116 targetPath = urlBuilder.normalize( | |
| 117 urlBuilder.join(urlBuilder.dirname(source.path), url)); | |
| 118 } | |
| 119 return new AssetId(package, targetPath); | |
| 120 } | |
| 121 | |
| 122 /** | |
| 123 * Generate the import url for a file described by [id], referenced by a file | |
| 124 * with [sourceId]. | |
| 125 */ | |
| 126 // TODO(sigmund): this should also be in barback (dartbug.com/12610) | |
| 127 String assetUrlFor(AssetId id, AssetId sourceId, TransformLogger logger, | |
| 128 {bool allowAssetUrl: false}) { | |
| 129 // use package: and asset: urls if possible | |
| 130 if (id.path.startsWith('lib/')) { | |
| 131 return 'package:${id.package}/${id.path.substring(4)}'; | |
| 132 } | |
| 133 | |
| 134 if (id.path.startsWith('asset/')) { | |
| 135 if (!allowAssetUrl) { | |
| 136 logger.error("asset urls not allowed. " | |
| 137 "Don't know how to refer to $id from $sourceId"); | |
| 138 return null; | |
| 139 } | |
| 140 return 'asset:${id.package}/${id.path.substring(6)}'; | |
| 141 } | |
| 142 | |
| 143 // Use relative urls only if it's possible. | |
| 144 if (id.package != sourceId.package) { | |
| 145 logger.error("don't know how to refer to $id from $sourceId"); | |
| 146 return null; | |
| 147 } | |
| 148 | |
| 149 var builder = path.url; | |
| 150 return builder.relative(builder.join('/', id.path), | |
| 151 from: builder.join('/', builder.dirname(sourceId.path))); | |
| 152 } | |
| 153 | |
| 154 | |
| 155 /** Convert system paths to asset paths (asset paths are posix style). */ | |
| 156 String _systemToAssetPath(String assetPath) { | |
| 157 if (path.Style.platform != path.Style.windows) return assetPath; | |
| 158 return path.posix.joinAll(path.split(assetPath)); | |
| 159 } | |
| OLD | NEW |