Index: initialize/lib/build/initializer_plugin.dart |
diff --git a/initialize/lib/build/initializer_plugin.dart b/initialize/lib/build/initializer_plugin.dart |
deleted file mode 100644 |
index 8822dc4f7e397b7daa741de704f023c25c19ea0a..0000000000000000000000000000000000000000 |
--- a/initialize/lib/build/initializer_plugin.dart |
+++ /dev/null |
@@ -1,294 +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.build.initializer_plugin; |
- |
-import 'package:analyzer/src/generated/ast.dart'; |
-import 'package:analyzer/src/generated/element.dart'; |
-import 'package:barback/barback.dart'; |
-import 'package:code_transformers/resolver.dart'; |
-import 'package:initialize/transformer.dart'; |
-import 'package:path/path.dart' as path; |
- |
-/// A plug which allows an initializer to write out an [InitEntry] given some |
-/// [InitializerData] from an annotation that was found. |
-abstract class InitializerPlugin { |
- /// Whether or not this plugin should be applied to an [Initializer] given |
- /// some [InitializerData]. If [true] is returned then this plugin will take |
- /// ownership of this [InitializerData] and no subsequent plugins will have |
- /// an opportunity to access it. |
- bool shouldApply(InitializerPluginData data); |
- |
- /// Returns a [String] or [null]. The [String] should represent dart code |
- /// which creates a new [InitEntry] and that entry is added to the static |
- /// initializers list. If [null] is returned then no entry is added at all for |
- /// this [InitializerData]. |
- String apply(InitializerPluginData data); |
-} |
- |
-/// A class which wraps all the default data passed to an [InitializerPlugin] |
-/// for each annotation. |
-class InitializerPluginData { |
- final InitializerData initializer; |
- final AssetId bootstrapId; |
- final Map<LibraryElement, String> libraryPrefixes; |
- final TransformLogger logger; |
- final Resolver resolver; |
- InitializerPluginData(this.initializer, this.bootstrapId, |
- this.libraryPrefixes, this.resolver, this.logger); |
-} |
- |
-/// The basic [InitializerPlugin]. This generates a new [InitEntry] to be added |
-/// to the static initializers list, and applies to every item it sees. |
-class DefaultInitializerPlugin implements InitializerPlugin { |
- const DefaultInitializerPlugin(); |
- |
- /// Applies to everything. Put other plugins before this one to override this |
- /// behaviour. |
- bool shouldApply(InitializerPluginData data) => true; |
- |
- /// Creates a normal [InitEntry] string. |
- String apply(InitializerPluginData pluginData) { |
- var target = buildTarget(pluginData); |
- var meta = buildMeta(pluginData); |
- return 'new InitEntry($meta, $target)'; |
- } |
- |
- /// Builds a [String] representing the meta of an [InitEntry] given an |
- /// [ElementAnnotation] that was found. |
- String buildMeta(InitializerPluginData pluginData) { |
- var logger = pluginData.logger; |
- var element = pluginData.initializer.targetElement; |
- var elementAnnotation = pluginData.initializer.annotationElement; |
- var elementAnnotationElement = elementAnnotation.element; |
- var libraryPrefixes = pluginData.libraryPrefixes; |
- if (elementAnnotationElement is ConstructorElement) { |
- return buildConstructorMeta(elementAnnotation, pluginData); |
- } else if (elementAnnotationElement is PropertyAccessorElement) { |
- return buildPropertyMeta(elementAnnotation, pluginData); |
- } else { |
- logger.error('Unsupported annotation type. Only constructors and ' |
- 'properties are supported as initializers.'); |
- } |
- return null; |
- } |
- |
- /// Builds a [String] representing the meta of an [InitEntry] given an |
- /// [ElementAnnotation] whose element was a [ConstructorElement]. |
- String buildConstructorMeta( |
- ElementAnnotation elementAnnotation, InitializerPluginData pluginData) { |
- var logger = pluginData.logger; |
- var node = pluginData.initializer.targetNode; |
- var metaPrefix = |
- pluginData.libraryPrefixes[elementAnnotation.element.library]; |
- |
- var annotation = pluginData.initializer.annotationNode; |
- if (annotation == null) { |
- logger.error( |
- 'Initializer annotations are only supported on libraries, classes, ' |
- 'and top level methods. Found $node.'); |
- } |
- var clazz = annotation.name; |
- var constructor = annotation.constructorName == null |
- ? '' |
- : '.${annotation.constructorName}'; |
- var args = buildArgumentList(annotation.arguments, pluginData); |
- return 'const $metaPrefix.${clazz}$constructor$args'; |
- } |
- |
- /// Builds a [String] representing the meta of an [InitEntry] given an |
- /// [ElementAnnotation] whose element was a [PropertyAccessorElement]. |
- String buildPropertyMeta( |
- ElementAnnotation annotation, InitializerPluginData pluginData) { |
- var metaPrefix = pluginData.libraryPrefixes[annotation.element.library]; |
- return '$metaPrefix.${annotation.element.name}'; |
- } |
- |
- /// Builds a [String] for the target of an [InitEntry] given an [Element] that |
- /// was annotated. |
- String buildTarget(InitializerPluginData pluginData) { |
- var element = pluginData.initializer.targetElement; |
- var logger = pluginData.logger; |
- if (element is LibraryElement) { |
- return buildLibraryTarget(element, pluginData); |
- } else if (element is ClassElement) { |
- return buildClassTarget(element, pluginData); |
- } else if (element is FunctionElement) { |
- return buildFunctionTarget(element, pluginData); |
- } else { |
- logger.error('Initializers can only be applied to top level functions, ' |
- 'libraries, and classes.'); |
- } |
- return null; |
- } |
- |
- /// Builds a [String] for the target of an [InitEntry] given [element] which |
- /// is an annotated class. |
- String buildClassTarget( |
- ClassElement element, InitializerPluginData pluginData) => |
- buildSimpleTarget(element, pluginData); |
- |
- /// Builds a [String] for the target of an [InitEntry] given [element] which |
- /// is an annotated function. |
- String buildFunctionTarget( |
- FunctionElement element, InitializerPluginData pluginData) => |
- buildSimpleTarget(element, pluginData); |
- |
- /// Builds a [String] for the target of an [InitEntry] for a simple [Element]. |
- /// This is just the library prefix followed by the element name. |
- String buildSimpleTarget(Element element, InitializerPluginData pluginData) => |
- '${pluginData.libraryPrefixes[element.library]}.${element.name}'; |
- |
- /// Builds a [String] for the target of an [InitEntry] given [element] which |
- /// is an annotated library. |
- String buildLibraryTarget( |
- LibraryElement element, InitializerPluginData pluginData) { |
- var bootstrapId = pluginData.bootstrapId; |
- var logger = pluginData.logger; |
- var segments = element.source.uri.pathSegments; |
- var package = segments[0]; |
- var libraryPath; |
- var packageString; |
- if (bootstrapId.package == package && |
- bootstrapId.path.startsWith('${segments[1]}/')) { |
- // reset `package` to null, we will do a relative path in this case. |
- packageString = 'null'; |
- libraryPath = 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') { |
- packageString = "'$package'"; |
- libraryPath = path.url.joinAll(segments.getRange(2, segments.length)); |
- } else { |
- logger.error('Unable to import `${element.source.uri.path}` from ' |
- '${bootstrapId.path}.'); |
- } |
- |
- return "const LibraryIdentifier" |
- "(#${element.name}, $packageString, '$libraryPath')"; |
- } |
- |
- /// Builds a [String] representing an [ArgumentList] taking into account the |
- /// [libraryPrefixes] from [pluginData]. |
- String buildArgumentList( |
- ArgumentList args, InitializerPluginData pluginData) { |
- var buffer = new StringBuffer(); |
- buffer.write('('); |
- var first = true; |
- for (var arg in args.arguments) { |
- if (!first) buffer.write(', '); |
- first = false; |
- |
- Expression expression; |
- if (arg is NamedExpression) { |
- buffer.write('${arg.name.label.name}: '); |
- expression = arg.expression; |
- } else { |
- expression = arg; |
- } |
- |
- buffer.write(buildExpression(expression, pluginData)); |
- } |
- buffer.write(')'); |
- return buffer.toString(); |
- } |
- |
- /// Builds a [String] representing [expression] taking into account the |
- /// [libraryPrefixes] from [pluginData]. |
- String buildExpression( |
- Expression expression, InitializerPluginData pluginData) { |
- var logger = pluginData.logger; |
- var libraryPrefixes = pluginData.libraryPrefixes; |
- var buffer = new StringBuffer(); |
- if (expression is StringLiteral && expression.stringValue != null) { |
- buffer.write(_stringValue(expression.stringValue)); |
- } else if (expression is BooleanLiteral || |
- expression is DoubleLiteral || |
- expression is IntegerLiteral || |
- expression is NullLiteral) { |
- buffer.write('${expression}'); |
- } else if (expression is ListLiteral) { |
- buffer.write('const ['); |
- var first = true; |
- for (Expression listExpression in expression.elements) { |
- if (!first) buffer.write(', '); |
- first = false; |
- buffer.write(buildExpression(listExpression, pluginData)); |
- } |
- buffer.write(']'); |
- } else if (expression is MapLiteral) { |
- buffer.write('const {'); |
- var first = true; |
- for (MapLiteralEntry entry in expression.entries) { |
- if (!first) buffer.write(', '); |
- first = false; |
- buffer.write(buildExpression(entry.key, pluginData)); |
- buffer.write(': '); |
- buffer.write(buildExpression(entry.value, pluginData)); |
- } |
- buffer.write('}'); |
- } else if (expression is Identifier) { |
- var element = expression.bestElement; |
- if (element == null) { |
- logger.error('Unable to get `bestElement` for expression: $expression'); |
- } else if (!element.isPublic) { |
- // Inline the evaluated value of private identifiers. |
- buffer.write(_evaluateExpression(expression, pluginData)); |
- } else { |
- libraryPrefixes.putIfAbsent( |
- element.library, () => 'i${libraryPrefixes.length}'); |
- |
- buffer.write('${libraryPrefixes[element.library]}.'); |
- if (element is ClassElement) { |
- buffer.write(element.name); |
- } else if (element is PropertyAccessorElement) { |
- var variable = element.variable; |
- if (variable is FieldElement) { |
- buffer.write('${variable.enclosingElement.name}.'); |
- } |
- buffer.write('${variable.name}'); |
- } else { |
- logger.error('Unsupported argument to initializer constructor.'); |
- } |
- } |
- } else if (expression is PropertyAccess) { |
- buffer.write(buildExpression(expression.target, pluginData)); |
- buffer.write('.${expression.propertyName}'); |
- } else if (expression is InstanceCreationExpression) { |
- logger.error('Unsupported expression in initializer, found $expression. ' |
- 'Instance creation expressions are not supported (yet). Instead, ' |
- 'please assign it to a const variable and use that instead.'); |
- } else { |
- buffer.write(_evaluateExpression(expression, pluginData)); |
- } |
- return buffer.toString(); |
- } |
- |
- _evaluateExpression(Expression expression, InitializerPluginData pluginData) { |
- var logger = pluginData.logger; |
- var result = pluginData.resolver.evaluateConstant( |
- pluginData.initializer.targetElement.library, expression); |
- if (!result.isValid) { |
- logger.error('Invalid expression in initializer, found $expression. ' |
- 'And got the following errors: ${result.errors}.'); |
- return null; |
- } |
- var value = result.value.value; |
- if (value == null) { |
- logger.error('Unsupported expression in initializer, found ' |
- '$expression. Please file a bug at ' |
- 'https://github.com/dart-lang/initialize/issues'); |
- return null; |
- } |
- |
- if (value is String) value = _stringValue(value); |
- return value; |
- } |
- |
- // Returns an expression for a string value. Wraps it in single quotes and |
- // escapes existing single quotes and escapes. |
- _stringValue(String value) { |
- value = value.replaceAll(r'\', r'\\').replaceAll(r"'", r"\'"); |
- return "'$value'"; |
- } |
-} |