blob: 9474d6985f6debedf53c3f45a2746f54028c5f38 [file] [log] [blame]
// Copyright (c) 2015, 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 'package:analyzer/analyzer.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:barback/barback.dart';
import 'package:initialize/transformer.dart';
import 'package:path/path.dart' as path;
import '../src/normalize_path.dart';
/// [InitializerPlugin] for @HtmlImport annotations. This records all paths
/// seen, normalizes them relative to the entry point, and records the values in
/// [importPaths].
/// Note: This does nothing with the paths on its own, a separate step needs to
/// add the imports to the entry point document.
class HtmlImportAnnotationRecorder implements InitializerPlugin {
/// All the normalized import paths that were seen.
final Set<String> importPaths = new Set<String>();
TransformLogger _logger;
/// Applies to anything named `HtmlImport` which annotates a library.
bool shouldApply(InitializerPluginData pluginData) {
var annotationElement = pluginData.initializer.annotationNode.element;
var logger = pluginData.logger;
DartType type;
if (annotationElement is ConstructorElement) {
type = annotationElement.returnType;
} else if (annotationElement is PropertyAccessorElement) {
type = annotationElement.variable.propagatedType;
if (type == null) {
type = pluginData.resolver.evaluateConstant(annotationElement.library,;
} else {
logger.error('Unsupported annotation type. Only constructors and '
'properties are supported as initializers.');
return false;
if ( != 'HtmlImport') return false;
if (pluginData.initializer.targetElement is! LibraryElement) {
logger.error('Invalid HtmlImport annotation on non-library element.');
return false;
return true;
/// Records the normalized url and returns [null] so that no [InitEntry] will
/// be created.
String apply(InitializerPluginData pluginData) {
var bootstrapId = pluginData.bootstrapId;
var logger = pluginData.logger;
var annotation = pluginData.initializer.annotationNode;
var annotationElement = pluginData.initializer.annotationElement;
var element = pluginData.initializer.targetElement as LibraryElement;
var resolver = pluginData.resolver;
var libraryDirective =
pluginData.initializer.targetNode.parent.parent as LibraryDirective;
var originalImportPath;
if (annotationElement.element is PropertyAccessorElement) {
originalImportPath = resolver.evaluateConstant(
} else {
assert(annotationElement.element is ConstructorElement);
originalImportPath = resolver.evaluateConstant(element.library,
var libPath;
var segments = element.source.uri.pathSegments;
var package = segments[0];
if (bootstrapId.package == package &&
bootstrapId.path.startsWith('${segments[1]}/')) {
package = null;
libPath = path.url.relative(
path.url.joinAll(segments.getRange(1, segments.length)),
from: path.url.dirname(path.url.join(bootstrapId.path)));
} else if (segments[1] == 'lib') {
libPath = path.url.joinAll(segments.getRange(2, segments.length));
} else {
logger.error('Unable to import `${element.source.uri.path}` from '
return null;
.add(normalizeHtmlImportPath(originalImportPath, package, libPath));
// Don't emit an InitEntry.
return null;