Fix normalization of relative paths inside of deep relative imports

R=sigmund@google.com

Review URL: https://codereview.chromium.org//993423004
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4f998f4..fc10126 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+#### 0.10.5+3
+  * Fix normalization of relative paths inside of deep relative imports,
+    https://github.com/dart-lang/polymer-dart/issues/30.
+
 #### 0.10.5+2
   * Append html imports in front of the dart script tag, if one exists in
     `document.head`.
diff --git a/lib/build/html_import_annotation_recorder.dart b/lib/build/html_import_annotation_recorder.dart
index e517e33..c320862 100644
--- a/lib/build/html_import_annotation_recorder.dart
+++ b/lib/build/html_import_annotation_recorder.dart
@@ -61,8 +61,9 @@
 
     var originalImportPath;
     if (annotationElement.element is PropertyAccessorElement) {
-      originalImportPath = resolver.evaluateConstant(element.library,
-          annotation.name).value.fields['filePath'].stringValue;
+      originalImportPath = resolver.evaluateConstant(
+              element.library, annotation.name).value.fields[
+          'filePath'].stringValue;
     } else {
       assert(annotationElement.element is ConstructorElement);
       originalImportPath = resolver.evaluateConstant(element.library,
diff --git a/lib/build/import_crawler.dart b/lib/build/import_crawler.dart
index c655efc..e1b6e48 100644
--- a/lib/build/import_crawler.dart
+++ b/lib/build/import_crawler.dart
@@ -14,13 +14,16 @@
 
 /// Information about an html import found in a document.
 class ImportData {
+  /// The [AssetId] where the html import appeared.
+  final AssetId fromId;
+
   /// The [Document] where the html import appeared.
   final Document document;
 
   /// The html import element itself.
   final Element element;
 
-  ImportData(this.document, this.element);
+  ImportData(this.document, this.element, {this.fromId});
 }
 
 /// A crawler for html imports.
@@ -45,18 +48,19 @@
     var documents = new LinkedHashMap<AssetId, ImportData>();
     var seen = new Set<AssetId>();
 
-    Future doCrawl(AssetId assetId, [Element import, Document document]) {
+    Future doCrawl(AssetId assetId,
+        {Element import, Document document, AssetId from}) {
       if (seen.contains(assetId)) return null;
       seen.add(assetId);
 
       Future crawlImports(Document document) {
         var imports = document.querySelectorAll('link[rel="import"]');
-        var done =
-            Future.forEach(imports, (i) => doCrawl(_importId(assetId, i), i));
+        var done = Future.forEach(imports,
+            (i) => doCrawl(_importId(assetId, i), import: i, from: assetId));
 
         // Add this document after its dependencies.
         return done.then((_) {
-          documents[assetId] = new ImportData(document, import);
+          documents[assetId] = new ImportData(document, import, fromId: from);
         });
       }
 
@@ -73,8 +77,8 @@
       }
     }
 
-    return
-      doCrawl(_primaryInputId, null, _primaryDocument).then((_) => documents);
+    return doCrawl(_primaryInputId, document: _primaryDocument)
+        .then((_) => documents);
   }
 
   AssetId _importId(AssetId source, Element import) {
diff --git a/lib/build/import_inliner.dart b/lib/build/import_inliner.dart
index 9101419..4336587 100644
--- a/lib/build/import_inliner.dart
+++ b/lib/build/import_inliner.dart
@@ -104,7 +104,7 @@
           .querySelectorAll('script[type="$dartType"]')
           .forEach((script) => script.remove());
       // Normalize urls in attributes and inline css.
-      new _UrlNormalizer(primaryInput, asset, logger).visit(document);
+      new _UrlNormalizer(data.fromId, asset, logger).visit(document);
       // Replace the import with its contents by appending the nodes
       // immediately before the import one at a time, and then removing the
       // import from the document.
@@ -266,7 +266,6 @@
 
     var id = uriToAssetId(sourceId, hrefToParse, logger, span);
     if (id == null) return href;
-    var primaryId = primaryInput;
 
     // Build the new path, placing back any suffixes that we stripped earlier.
     var prefix =
@@ -282,17 +281,17 @@
       return '${topLevelPath}assets/${id.package}/${newPath.substring(6)}';
     }
 
-    if (primaryId.package != id.package) {
+    if (primaryInput.package != id.package) {
       // Technically we shouldn't get there
       logger.error(internalErrorDontKnowHowToImport
-              .create({'target': id, 'source': primaryId, 'extra': ''}),
+              .create({'target': id, 'source': primaryInput, 'extra': ''}),
           span: span);
       return href;
     }
 
     var builder = path.url;
     return builder.normalize(builder.relative(builder.join('/', newPath),
-        from: builder.join('/', builder.dirname(primaryId.path))));
+        from: builder.join('/', builder.dirname(primaryInput.path))));
   }
 }
 
diff --git a/pubspec.yaml b/pubspec.yaml
index d26edac..fa01acf 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: web_components
-version: 0.10.5+2
+version: 0.10.5+3
 author: Polymer.dart Authors <web-ui-dev@dartlang.org>
 homepage: https://www.dartlang.org/polymer-dart/
 description: >
diff --git a/test/build/import_crawler_test.dart b/test/build/import_crawler_test.dart
index c140c09..42f85bd 100644
--- a/test/build/import_crawler_test.dart
+++ b/test/build/import_crawler_test.dart
@@ -34,11 +34,11 @@
     }
   }
 
-  Future crawlDocument(
-      Transform transform, BuildLogger logger, [Document document]) {
+  Future crawlDocument(Transform transform, BuildLogger logger,
+      [Document document]) {
     var primaryInput = transform.primaryInput;
-    var crawler = new ImportCrawler(
-        transform, primaryInput.id, logger, primaryDocument: document);
+    var crawler = new ImportCrawler(transform, primaryInput.id, logger,
+        primaryDocument: document);
     return crawler.crawlImports().then((docs) {
       documents = docs;
       transform.addOutput(new Asset.fromString(
diff --git a/test/build/import_inliner_test.dart b/test/build/import_inliner_test.dart
index 1581355..7e060a2 100644
--- a/test/build/import_inliner_test.dart
+++ b/test/build/import_inliner_test.dart
@@ -735,6 +735,28 @@
         <img src="{{bar[0]}}/{{baz[1]}}.{{extension}}">
         </body></html>''',
   }, null, StringFormatter.noNewlinesOrSurroundingWhitespace);
+
+  testPhases('relative paths in deep imports', phases, {
+    'a|web/test.html': '''
+        <!DOCTYPE html><html><head>
+        <link rel="import" href="foo/foo.html">
+        </head></html>''',
+    'a|web/foo/foo.html': '''
+        <link rel="import" href="bar.html">''',
+    'a|web/foo/bar.html': '''
+        <style rel="stylesheet" href="baz.css"></style>
+        <style rel="stylesheet" href="../css/zap.css"></style>''',
+    'a|web/foo/baz.css': '',
+    'a|web/css/zap.css': '',
+  }, {
+    'a|web/test.html': '''
+        <!DOCTYPE html><html><head></head><body>
+        <div hidden="">
+          <style rel="stylesheet" href="foo/baz.css"></style>
+          <style rel="stylesheet" href="css/zap.css"></style>
+        </div>
+        </body></html>''',
+  }, [], StringFormatter.noNewlinesOrSurroundingWhitespace);
 }
 
 void entryPointTests() {
diff --git a/test/custom_element_test.dart b/test/custom_element_test.dart
index ced6601..2418def 100644
--- a/test/custom_element_test.dart
+++ b/test/custom_element_test.dart
@@ -75,7 +75,6 @@
       });
     });
 
-
     test('extends input element', () {
       expect(document.querySelector('input') is ExtendedElement, isTrue);
       container.append(new ExtendedElement());