From 3317624c491e679712a9641264e61edb08f35a8b Mon Sep 17 00:00:00 2001 From: thosakwe Date: Mon, 19 Sep 2016 16:24:26 -0400 Subject: [PATCH] Barback transformer --- lib/browser.dart | 1 + lib/transformer.dart | 93 +++++++++++++++++++++++++++++++++++++++++++ pubspec.yaml | 6 ++- test/all_tests.dart | 5 ++- test/transformer.dart | 26 ++++++++++++ 5 files changed, 128 insertions(+), 3 deletions(-) create mode 100644 lib/browser.dart create mode 100644 lib/transformer.dart create mode 100644 test/transformer.dart diff --git a/lib/browser.dart b/lib/browser.dart new file mode 100644 index 00000000..a1c7d8c8 --- /dev/null +++ b/lib/browser.dart @@ -0,0 +1 @@ +external dynamic config(String key); diff --git a/lib/transformer.dart b/lib/transformer.dart new file mode 100644 index 00000000..aa84f58e --- /dev/null +++ b/lib/transformer.dart @@ -0,0 +1,93 @@ +import 'dart:async'; +import 'dart:convert'; +import 'package:barback/barback.dart'; +import 'package:analyzer/analyzer.dart'; +import 'package:angel_framework/angel_framework.dart'; +import 'angel_configuration.dart'; + +class ConfigurationTransformer extends Transformer { + final BarbackSettings _settings; + + @override + String get allowedExtensions => ".dart"; + + ConfigurationTransformer.asPlugin(this._settings) {} + + Future apply(Transform transform) async { + var app = new Angel(); + + await app.configure(loadConfigurationFile( + directoryPath: _settings.configuration["dir"] ?? "./config", + overrideEnvironmentName: _settings.configuration["env"])); + + var text = await transform.primaryInput.readAsString(); + var compilationUnit = parseCompilationUnit(text); + var visitor = new ConfigAstVisitor(app.properties); + visitor.visitCompilationUnit(compilationUnit); + + await for (Map replaced in visitor.onReplaced) { + text = text.replaceAll(replaced["needle"], replaced["with"]); + } + + transform.addOutput(new Asset.fromString(transform.primaryInput.id, text)); + } +} + +class ConfigAstVisitor extends GeneralizingAstVisitor { + Map _config; + var _onReplaced = new StreamController(); + String _prefix = ""; + Stream get onReplaced => _onReplaced.stream; + + ConfigAstVisitor(this._config); + + bool isConfigMethod(Expression function) => + function is SimpleIdentifier && function.name == "${_prefix}config"; + + resolveItem(String key) { + var split = key.split("."); + var parent = _config; + + for (int i = 0; i < split.length; i++) { + if (parent != null && parent is Map) parent = parent[split[i]]; + } + + return parent; + } + + @override + visitCompilationUnit(CompilationUnit ctx) { + var result = super.visitCompilationUnit(ctx); + _onReplaced.close(); + return result; + } + + @override + visitImportDirective(ImportDirective ctx) { + String uri = ctx.uri.stringValue; + + if (uri == "package:angel_configuration/browser.dart") { + _onReplaced.add({"needle": ctx.toString(), "with": ""}); + + if (ctx.asKeyword != null) { + _prefix = ctx.prefix.name; + } + } + + return super.visitImportDirective(ctx); + } + + @override + visitExpression(Expression ctx) { + if (ctx is MethodInvocation) { + if (isConfigMethod(ctx.function)) { + StringLiteral key = ctx.argumentList.arguments[0]; + var resolved = resolveItem(key.stringValue); + + _onReplaced + .add({"needle": ctx.toString(), "with": JSON.encode(resolved)}); + } + } + return super.visitExpression(ctx); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 90903fe2..5ed37d7a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,10 +1,12 @@ name: angel_configuration description: YAML configuration loader for Angel. -version: 1.0.1 +version: 1.0.1+1 author: thosakwe homepage: https://github.com/angel-dart/angel_configuration dependencies: + analyzer: ">=0.28.1 <0.29.0" angel_framework: ">=1.0.0-dev < 2.0.0" + barback: ">=0.15.2 < 0.16.0" yaml: ">= 2.1.8 < 2.2.0" dev_dependencies: - test: ">= 0.12.13 < 0.13.0" \ No newline at end of file + test: ">= 0.12.13 < 0.13.0" diff --git a/test/all_tests.dart b/test/all_tests.dart index e76497de..cc5b752a 100644 --- a/test/all_tests.dart +++ b/test/all_tests.dart @@ -1,6 +1,7 @@ import 'package:angel_framework/angel_framework.dart'; import 'package:angel_configuration/angel_configuration.dart'; import 'package:test/test.dart'; +import 'transformer.dart' as transformer; main() async { // Note: Set ANGEL_ENV to 'development' @@ -25,4 +26,6 @@ main() async { expect(angel.properties['hello'], equals('goodbye')); expect(angel.properties['foo']['version'], equals('baz')); }); -} \ No newline at end of file + + group("transformer", transformer.main); +} diff --git a/test/transformer.dart b/test/transformer.dart new file mode 100644 index 00000000..950fef6e --- /dev/null +++ b/test/transformer.dart @@ -0,0 +1,26 @@ +import 'package:analyzer/analyzer.dart'; +import 'package:angel_configuration/transformer.dart'; +import 'package:test/test.dart'; + +main() { + test("simple replacement", () async { + var visitor = new ConfigAstVisitor({"foo": "bar"}); + var source = ''' + import 'package:angel_configuration/browser.dart'; + + main() async { + var foo = config('foo'); + } + '''; + + var compilationUnit = parseCompilationUnit(source); + visitor.visitCompilationUnit(compilationUnit); + + var replaced = await visitor.onReplaced.take(2).last; + + expect(replaced["needle"], equals("config('foo')")); + expect(replaced["with"], equals('"bar"')); + + print(source.replaceAll(replaced["needle"], replaced["with"])); + }); +}