0 purchases
swift composer
swift_composer #
- warning: this module is experimental and under development. It's API is subjected to change
copied to clipboard
Swift Composer aims to turn dart modules into plugable application parts.
It uses source_gen to generate final application logic depending on imported
modules and configuration hence no boilerplate code is created.
This module powers 'swift.shop' app engine.
It is used to generate plugable client and server side routing, auto-serializable data models,
configurable layouts and widgets system and more.
Installation #
add swift_composer to your dependencies in pubspec.yaml:
dependencies:
swift_composer: any
copied to clipboard
declare a compiled part in your final application code:
import 'package:swift_composer/swift_composer.dart';
import 'package:some_plugin';
part 'main.c.dart';
void main() {
$om.some_compiled_entrypoint.run();
}
copied to clipboard
build .c.dart part
pub run build_runner build
copied to clipboard
If you are creating a web package the build will be executed automatically with
webdev serve/build.
Features #
Requirements #
For any class to use swift composer features it needs to be declared as abstract
and decorated with @Compose annotation. This allows code generator to generate
a final class with compiled methods, plugins and dependency injections.
@Compose
abstract class Foo {
}
copied to clipboard
Class Names #
@Compose
abstract class Foo {
@InjectClassName
String get className;
@InjectClassNames
List<String> get classNames;
}
copied to clipboard
All instances of Test and its subtypes will have className field populated
with this class full name and classNames populated with full class hierarchy
path.
Above is useful for serialization as this field will contain source class name
even after compilation to *.js etc.
Dependency Injection #
@Compose
abstract class Bar {
@Require
String barRequiredField;
}
@Compose
abstract class Test {
@Inject
Foo get injectedFoo;
@Factory
Foo createFoo();
@Factory
Bar createBar(String barRequiredField);
}
copied to clipboard
Methods decorated with Factory will create a compiled subtype of return type.
Exact type returned will defined by imported modules and DI configuration.
For classes without any dependencies required for creation you can use Inject
annotation to generate shared instance.
Finding Class Subtypes
@Compose
abstract class Test {
@InjectInstances
Map<String, Foo> get instances;
@SubtypeFactory
Foo createFoo(String className);
}
copied to clipboard
Method decorated with SubtypeFactory will return a subtype of Foo depending
on passed className parameter.
A getter decorated with InjectInstances will contain a map indexed with class
names of all requirements free subtypes of Foo.
Class Fields info and Compiled methods. #
Swift Composer adds tools to generate info of final class fields that can be
used for example to generate JSON serialization.
const JsonField = true;
@Compose
abstract class TestSerializable {
@InjectClassName
String get className;
@JsonField
String foo;
@JsonField
String bar;
Map toJson() {
Map ret = new Map();
ret['className'] = className;
this.fieldsToJson(ret);
return ret;
}
@Compile
void fieldsToJson(Map target);
@CompileFieldsOfType
@AnnotatedWith(JsonField)
void _fieldsToJsonString(Map target, String name, String field) {
target[name] = field;
}
@CompileFieldsOfType
@AnnotatedWith(JsonField)
void _fieldsToJsonInt(Map target, String name, int field) {
target[name] = field;
}
}
copied to clipboard
In above example, all subtypes of TestSerializable will have toJson that
will return all fields decorated with @JsonField serialized.
Dart tree shaking algorithms will clear compiled code out of unused stubs.
Type Plugins #
Type plugins can modify objects data and behavior.
Fields compilation method works with plugins and will also compile plugin fields
so we can add a plugin for TestSerializable from previous example.
abstract class TestPlugin extends TypePlugin<TestSerializable> {
@Field
String extraField = 'test';
}
copied to clipboard
Now, calling toJson should return something like:
{
'className' : 'TestSerializable',
'foo' : 'something',
'bar' : 10,
'testPlugin.extraField': 'test'
}
copied to clipboard
We can also extend / change decorated classes behaviors using MethodPlugin annotations.
Every public method in parent class:
bool validate(int foo, int bar) {
return foo > bar;
}
copied to clipboard
Plugin class can customize behavior of such methods:
@MethodPlugin
List<dynamic> beforeValidate(int foo, int bar) {
bar = bar + 1;
return [foo, bar];
}
@MethodPlugin
bool afterValidate(bool ret) {
return !ret;
}
copied to clipboard
Development Info #
Running tests:
dart run build_runner build && dart test/swift_composer_test.dart
copied to clipboard
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.