Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(30)

Unified Diff: initialize/lib/transformer.dart

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « initialize/lib/src/static_loader.dart ('k') | initialize/pubspec.yaml » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: initialize/lib/transformer.dart
diff --git a/initialize/lib/transformer.dart b/initialize/lib/transformer.dart
deleted file mode 100644
index a1f01fa1650f4fe972dc854e516447cafb442f8d..0000000000000000000000000000000000000000
--- a/initialize/lib/transformer.dart
+++ /dev/null
@@ -1,464 +0,0 @@
-// 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.
-library initialize.transformer;
-
-import 'dart:async';
-import 'dart:collection' show Queue;
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/element.dart';
-import 'package:barback/barback.dart';
-import 'package:code_transformers/assets.dart';
-import 'package:code_transformers/resolver.dart';
-import 'package:code_transformers/src/dart_sdk.dart' as dart_sdk;
-import 'package:dart_style/dart_style.dart';
-import 'package:glob/glob.dart';
-import 'package:html/dom.dart' as dom;
-import 'package:html/parser.dart' show parse;
-import 'package:path/path.dart' as path;
-
-import 'build/initializer_plugin.dart';
-export 'build/initializer_plugin.dart';
-
-/// Create a new [Asset] which inlines your [Initializer] annotations into
-/// a new file that bootstraps your application.
-Asset generateBootstrapFile(Resolver resolver, Transform transform,
- AssetId primaryAssetId, AssetId newEntryPointId,
- {bool errorIfNotFound: true, List<InitializerPlugin> plugins,
- bool appendDefaultPlugin: true}) {
- if (appendDefaultPlugin) {
- if (plugins == null) plugins = [];
- plugins.add(const DefaultInitializerPlugin());
- }
- return new _BootstrapFileBuilder(
- resolver, transform, primaryAssetId, newEntryPointId, errorIfNotFound,
- plugins: plugins).run();
-}
-
-/// Transformer which removes the mirror-based initialization logic and replaces
-/// it with static logic.
-class InitializeTransformer extends Transformer {
- final Resolvers _resolvers;
- final Iterable<Glob> _entryPointGlobs;
- final bool _errorIfNotFound;
- final List<InitializerPlugin> plugins;
-
- InitializeTransformer(List<String> entryPoints,
- {bool errorIfNotFound: true, this.plugins})
- : _entryPointGlobs = entryPoints.map((e) => new Glob(e)),
- _errorIfNotFound = errorIfNotFound,
- _resolvers = new Resolvers.fromMock(dart_sdk.mockSdkSources);
-
- factory InitializeTransformer.asPlugin(BarbackSettings settings) =>
- new InitializeTransformer(_readFileList(settings, 'entry_points'));
-
- bool isPrimary(AssetId id) => _entryPointGlobs.any((g) => g.matches(id.path));
-
- Future apply(Transform transform) {
- if (transform.primaryInput.id.path.endsWith('.dart')) {
- return _buildBootstrapFile(transform);
- } else if (transform.primaryInput.id.path.endsWith('.html')) {
- return transform.primaryInput.readAsString().then((html) {
- var document = parse(html);
- var originalDartFile =
- _findMainScript(document, transform.primaryInput.id, transform);
- return _buildBootstrapFile(transform, primaryId: originalDartFile)
- .then((AssetId newDartFile) {
- return _replaceEntryWithBootstrap(transform, document,
- transform.primaryInput.id, originalDartFile, newDartFile);
- });
- });
- } else {
- transform.logger.warning(
- 'Invalid entry point ${transform.primaryInput.id}. Must be either a '
- '.dart or .html file.');
- }
- return new Future.value();
- }
-
- // Returns the AssetId of the newly created bootstrap file.
- Future<AssetId> _buildBootstrapFile(Transform transform,
- {AssetId primaryId}) {
- if (primaryId == null) primaryId = transform.primaryInput.id;
- var newEntryPointId = new AssetId(primaryId.package,
- '${path.url.withoutExtension(primaryId.path)}.initialize.dart');
- return transform.hasInput(newEntryPointId).then((exists) {
- if (exists) {
- transform.logger
- .error('New entry point file $newEntryPointId already exists.');
- return null;
- }
-
- return _resolvers.get(transform, [primaryId]).then((resolver) {
- transform.addOutput(generateBootstrapFile(
- resolver, transform, primaryId, newEntryPointId,
- errorIfNotFound: _errorIfNotFound, plugins: plugins));
- resolver.release();
- return newEntryPointId;
- });
- });
- }
- // Finds the first (and only) dart script on an html page and returns the
- // [AssetId] that points to it
- AssetId _findMainScript(
- dom.Document document, AssetId entryPoint, Transform transform) {
- var scripts = document.querySelectorAll('script[type="application/dart"]');
- if (scripts.length != 1) {
- transform.logger.error('Expected exactly one dart script in $entryPoint '
- 'but found ${scripts.length}.');
- return null;
- }
-
- var src = scripts[0].attributes['src'];
- if (src == null) {
- // TODO(jakemac): Support inline scripts,
- transform.logger.error('Inline scripts are not supported at this time, '
- 'see https://github.com/dart-lang/initialize/issues/20.');
- return null;
- }
-
- return uriToAssetId(
- entryPoint, src, transform.logger, scripts[0].sourceSpan);
- }
-
- // Replaces script tags pointing to [originalDartFile] with [newDartFile] in
- // [entryPoint].
- void _replaceEntryWithBootstrap(Transform transform, dom.Document document,
- AssetId entryPoint, AssetId originalDartFile, AssetId newDartFile) {
- var found = false;
-
- var scripts = document
- .querySelectorAll('script[type="application/dart"]')
- .where((script) {
- var assetId = uriToAssetId(entryPoint, script.attributes['src'],
- transform.logger, script.sourceSpan);
- return assetId == originalDartFile;
- }).toList();
-
- if (scripts.length != 1) {
- transform.logger.error(
- 'Expected exactly one script pointing to $originalDartFile in '
- '$entryPoint, but found ${scripts.length}.');
- return;
- }
- scripts[0].attributes['src'] = path.url.relative(newDartFile.path,
- from: path.dirname(entryPoint.path));
- transform.addOutput(new Asset.fromString(entryPoint, document.outerHtml));
- }
-}
-
-// Class which builds a bootstrap file.
-class _BootstrapFileBuilder {
- final Resolver _resolver;
- final Transform _transform;
- final bool _errorIfNotFound;
- AssetId _entryPoint;
- AssetId _newEntryPoint;
-
- /// The resolved initialize library.
- LibraryElement _initializeLibrary;
- /// The resolved Initializer class from the initialize library.
- ClassElement _initializer;
-
- /// Queue for intialization annotations.
- final _initQueue = new Queue<InitializerData>();
- /// All the annotations we have seen for each element
- final _seenAnnotations = new Map<Element, Set<ElementAnnotation>>();
-
- /// The list of [InitializerPlugin]s to apply. The first plugin which asks to
- /// be applied to a given initializer is the only one that will apply.
- List<InitializerPlugin> _plugins;
-
- TransformLogger _logger;
-
- _BootstrapFileBuilder(this._resolver, this._transform, this._entryPoint,
- this._newEntryPoint, this._errorIfNotFound,
- {List<InitializerPlugin> plugins}) {
- _logger = _transform.logger;
- _initializeLibrary =
- _resolver.getLibrary(new AssetId('initialize', 'lib/initialize.dart'));
- if (_initializeLibrary != null) {
- _initializer = _initializeLibrary.getType('Initializer');
- } else if (_errorIfNotFound) {
- _logger.warning('Unable to read "package:initialize/initialize.dart". '
- 'This file must be imported via $_entryPoint or a transitive '
- 'dependency.');
- }
- _plugins = plugins != null ? plugins : [const DefaultInitializerPlugin()];
- }
-
- /// Creates and returns the new bootstrap file.
- Asset run() {
- var entryLib = _resolver.getLibrary(_entryPoint);
- _readLibraries(entryLib);
-
- return new Asset.fromString(_newEntryPoint, _buildNewEntryPoint(entryLib));
- }
-
- /// Reads Initializer annotations on this library and all its dependencies in
- /// post-order.
- void _readLibraries(LibraryElement library, [Set<LibraryElement> seen]) {
- if (seen == null) seen = new Set<LibraryElement>();
- seen.add(library);
-
- // Visit all our dependencies.
- for (var library in _sortedLibraryDependencies(library)) {
- // Don't include anything from the sdk.
- if (library.isInSdk) continue;
- if (seen.contains(library)) continue;
- _readLibraries(library, seen);
- }
-
- // Read annotations in this order: library, top level methods, classes.
- _readAnnotations(library);
- for (var method in _topLevelMethodsOfLibrary(library, seen)) {
- _readAnnotations(method);
- }
- for (var clazz in _classesOfLibrary(library, seen)) {
- readSuperClassAnnotations(InterfaceType superClass) {
- if (superClass == null) return;
- readSuperClassAnnotations(superClass.superclass);
- if (_readAnnotations(superClass.element) &&
- superClass.element.library != clazz.library) {
- _logger.warning(
- 'We have detected a cycle in your import graph when running '
- 'initializers on ${clazz.name}. This means the super class '
- '${superClass.name} has a dependency on this library '
- '(possibly transitive).');
- }
- }
- readSuperClassAnnotations(clazz.supertype);
- _readAnnotations(clazz);
- }
- }
-
- bool _readAnnotations(Element element) {
- var found = false;
- if (element.metadata.isEmpty) return found;
-
- var metaNodes;
- var node = element.node;
- if (node is SimpleIdentifier && node.parent is LibraryIdentifier) {
- metaNodes = node.parent.parent.metadata;
- } else if (node is ClassDeclaration || node is FunctionDeclaration) {
- metaNodes = node.metadata;
- } else {
- return found;
- }
-
- metaNodes.where((Annotation metaNode) {
- // First filter out anything that is not a Initializer.
- var meta = metaNode.elementAnnotation;
- var e = meta.element;
- if (e is PropertyAccessorElement) {
- return _isInitializer(e.variable.evaluationResult.value.type);
- } else if (e is ConstructorElement) {
- return _isInitializer(e.returnType);
- }
- return false;
- }).where((Annotation metaNode) {
- var meta = metaNode.elementAnnotation;
- _seenAnnotations.putIfAbsent(element, () => new Set<ElementAnnotation>());
- return !_seenAnnotations[element].contains(meta);
- }).forEach((Annotation metaNode) {
- var meta = metaNode.elementAnnotation;
- _seenAnnotations[element].add(meta);
- _initQueue.addLast(new InitializerData._(node, metaNode));
- found = true;
- });
- return found;
- }
-
- String _buildNewEntryPoint(LibraryElement entryLib) {
- var importsBuffer = new StringBuffer();
- var initializersBuffer = new StringBuffer();
- var libraryPrefixes = new Map<LibraryElement, String>();
-
- // Import the static_loader, initializer, and original entry point.
- importsBuffer
- .writeln("import 'package:initialize/src/static_loader.dart';");
- importsBuffer.writeln("import 'package:initialize/initialize.dart';");
- libraryPrefixes[entryLib] = 'i0';
-
- initializersBuffer.writeln('initializers.addAll([');
- while (_initQueue.isNotEmpty) {
- var next = _initQueue.removeFirst();
-
- libraryPrefixes.putIfAbsent(
- next.targetElement.library, () => 'i${libraryPrefixes.length}');
- libraryPrefixes.putIfAbsent(next.annotationElement.element.library,
- () => 'i${libraryPrefixes.length}');
-
- // Run the first plugin which asks to be ran and then stop.
- var data = new InitializerPluginData(
- next, _newEntryPoint, libraryPrefixes, _resolver, _logger);
- var plugin = _plugins.firstWhere((p) => p.shouldApply(data), orElse: () {
- _logger.error('No InitializerPlugin handled the annotation: '
- '${next.annotationElement} on: ${next.targetElement}.');
- });
- if (plugin == null) continue;
-
- var text = plugin.apply(data);
- if (text != null) initializersBuffer.writeln('$text,');
- }
- initializersBuffer.writeln(']);');
-
- libraryPrefixes
- .forEach((lib, prefix) => _writeImport(lib, prefix, importsBuffer));
-
- // TODO(jakemac): copyright and library declaration
- return new DartFormatter().format('''
-$importsBuffer
-main() {
-$initializersBuffer
- return i0.main();
-}
-''');
- }
-
- _writeImport(LibraryElement lib, String prefix, StringBuffer buffer) {
- AssetId id = (lib.source as dynamic).assetId;
-
- if (id.path.startsWith('lib/')) {
- var packagePath = id.path.replaceFirst('lib/', '');
- buffer.write("import 'package:${id.package}/${packagePath}'");
- } else if (id.package != _newEntryPoint.package) {
- _logger.error("Can't import `${id}` from `${_newEntryPoint}`");
- } else if (path.url.split(id.path)[0] ==
- path.url.split(_newEntryPoint.path)[0]) {
- var relativePath = path.url.relative(id.path,
- from: path.url.dirname(_newEntryPoint.path));
- buffer.write("import '${relativePath}'");
- } else {
- _logger.error("Can't import `${id}` from `${_newEntryPoint}`");
- }
- buffer.writeln(' as $prefix;');
- }
-
- bool _isInitializer(InterfaceType type) {
- // If `_initializer` wasn't found then it was never loaded (even
- // transitively), and so no annotations can be initializers.
- if (_initializer == null) return false;
- if (type == null) return false;
- if (type.element.type == _initializer.type) return true;
- if (_isInitializer(type.superclass)) return true;
- for (var interface in type.interfaces) {
- if (_isInitializer(interface)) return true;
- }
- return false;
- }
-
- /// Retrieves all top-level methods that are visible if you were to import
- /// [lib]. This includes exported methods from other libraries too.
- List<FunctionElement> _topLevelMethodsOfLibrary(
- LibraryElement library, Set<LibraryElement> seen) {
- var methods = [];
-
- var orderedExports = new List.from(library.exports)
- ..sort((a, b) => a.uriOffset.compareTo(b.uriOffset));
- for (var export in orderedExports) {
- if (seen.contains(export.exportedLibrary)) continue;
- methods.addAll(_topLevelMethodsOfLibrary(export.exportedLibrary, seen));
- }
-
- for (CompilationUnitElement unit in _orderedUnits(library)) {
- methods.addAll(new List.from(unit.functions)
- ..sort((a, b) => a.nameOffset.compareTo(b.nameOffset)));
- }
-
- return methods;
- }
-
- /// Retrieves all classes that are visible if you were to import [lib]. This
- /// includes exported classes from other libraries.
- List<ClassElement> _classesOfLibrary(
- LibraryElement library, Set<LibraryElement> seen) {
- var classes = [];
-
- var orderedExports = new List.from(library.exports)
- ..sort((a, b) => a.uriOffset.compareTo(b.uriOffset));
- for (var export in orderedExports) {
- if (seen.contains(export.exportedLibrary)) continue;
- classes.addAll(_classesOfLibrary(export.exportedLibrary, seen));
- }
-
- for (var unit in _orderedUnits(library)) {
- classes.addAll(new List.from(unit.types)
- ..sort((a, b) => a.nameOffset.compareTo(b.nameOffset)));
- }
-
- return classes;
- }
-
- List<CompilationUnitElement> _orderedUnits(LibraryElement library) {
- var definingUnit = library.definingCompilationUnit;
- // The first item is the source library, remove it for now.
- return new List.from(library.units)
- ..sort((a, b) {
- if (a == definingUnit) return 1;
- if (b == definingUnit) return -1;
- return a.uri.compareTo(b.uri);
- });
- }
-
- Iterable<LibraryElement> _sortedLibraryDependencies(LibraryElement library) {
- // TODO(jakemac): Investigate supporting annotations on part-of directives.
- getLibrary(UriReferencedElement element) {
- if (element is ImportElement) return element.importedLibrary;
- if (element is ExportElement) return element.exportedLibrary;
- }
-
- return (new List.from(library.imports)
- ..addAll(library.exports)
- ..sort((a, b) => a.nameOffset.compareTo(b.nameOffset))).map(getLibrary);
- }
-}
-
-/// An [Initializer] annotation and the target of that annotation.
-class InitializerData {
- /// The target [AstNode] of the annotation.
- final AstNode targetNode;
-
- /// The [Annotation] representing the annotation itself.
- final Annotation annotationNode;
-
- /// The [ElementAnnotation] representing the annotation itself.
- ElementAnnotation get annotationElement => annotationNode.elementAnnotation;
-
- /// The target [Element] of the annotation.
- Element get targetElement {
- if (targetNode is SimpleIdentifier &&
- targetNode.parent is LibraryIdentifier) {
- return (targetNode.parent.parent as LibraryDirective).element;
- } else if (targetNode is ClassDeclaration ||
- targetNode is FunctionDeclaration) {
- return (targetNode as dynamic).element;
- } else {
- return null;
- }
- }
-
- InitializerData._(this.targetNode, this.annotationNode);
-}
-
-// Reads a file list from a barback settings configuration field.
-_readFileList(BarbackSettings settings, String field) {
- var value = settings.configuration[field];
- if (value == null) return null;
- var files = [];
- bool error;
- if (value is List) {
- files = value;
- error = value.any((e) => e is! String);
- } else if (value is String) {
- files = [value];
- error = false;
- } else {
- error = true;
- }
- if (error) {
- print('Bad value for "$field" in the initialize transformer. '
- 'Expected either one String or a list of Strings.');
- }
- return files;
-}
« no previous file with comments | « initialize/lib/src/static_loader.dart ('k') | initialize/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698