blob: c655efc7aece41ee5fa0c9a46c2f402d50caa8b6 [file] [log] [blame]
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'dart:collection' show LinkedHashMap;
import 'package:code_transformers/assets.dart';
import 'package:code_transformers/messages/build_logger.dart';
import 'package:barback/barback.dart';
import 'package:html5lib/dom.dart' show Document, Element;
import 'common.dart';
import 'messages.dart';
/// Information about an html import found in a document.
class ImportData {
/// The [Document] where the html import appeared.
final Document document;
/// The html import element itself.
final Element element;
ImportData(this.document, this.element);
/// A crawler for html imports.
class ImportCrawler {
// Can be either an AggregateTransform or Transform.
final _transform;
final BuildLogger _logger;
final AssetId _primaryInputId;
// Optional parsed document for the primary id if available.
final Document _primaryDocument;
ImportCrawler(this._transform, this._primaryInputId, this._logger,
{Document primaryDocument})
: _primaryDocument = primaryDocument;
/// Returns a post-ordered map of [AssetId]'s to [ImportData]. The [AssetId]'s
/// represent an asset which was discovered via an html import, and the
/// [ImportData] represents the [Document] where it was discovered and the
/// html import [Element] itself.
Future<LinkedHashMap<AssetId, ImportData>> crawlImports() {
var documents = new LinkedHashMap<AssetId, ImportData>();
var seen = new Set<AssetId>();
Future doCrawl(AssetId assetId, [Element import, Document document]) {
if (seen.contains(assetId)) return null;
Future crawlImports(Document document) {
var imports = document.querySelectorAll('link[rel="import"]');
var done =
Future.forEach(imports, (i) => doCrawl(_importId(assetId, i), i));
// Add this document after its dependencies.
return done.then((_) {
documents[assetId] = new ImportData(document, import);
if (document != null) {
return crawlImports(document);
} else {
return _transform.readInputAsString(assetId).then((html) {
return crawlImports(parseHtml(html, assetId.path));
}).catchError((error) {
var span;
if (import != null) span = import.sourceSpan;
_logger.error(inlineImportFail.create({'error': error}), span: span);
doCrawl(_primaryInputId, null, _primaryDocument).then((_) => documents);
AssetId _importId(AssetId source, Element import) {
var url = import.attributes['href'];
return uriToAssetId(source, url, _transform.logger, import.sourceSpan);