Init repository

This commit is contained in:
Simon Binder 2019-02-03 13:56:31 +01:00
parent 5a450c8e76
commit 5abefa7494
52 changed files with 2258 additions and 78 deletions

4
.idea/encodings.xml Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
</project>

View File

@ -0,0 +1,626 @@
<component name="libraryTable">
<library name="Dart Packages" type="DartPackagesLibraryType">
<properties>
<option name="packageNameToDirsMap">
<entry key="analyzer">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/analyzer-0.34.3/lib" />
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/analyzer-0.35.0/lib" />
</list>
</value>
</entry>
<entry key="analyzer_plugin">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/analyzer_plugin-0.0.1-alpha.6/lib" />
</list>
</value>
</entry>
<entry key="args">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/args-1.5.1/lib" />
</list>
</value>
</entry>
<entry key="async">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/async-2.0.8/lib" />
</list>
</value>
</entry>
<entry key="boolean_selector">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/boolean_selector-1.0.4/lib" />
</list>
</value>
</entry>
<entry key="build">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build-1.1.0/lib" />
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build-1.1.1/lib" />
</list>
</value>
</entry>
<entry key="build_config">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build_config-0.3.1+4/lib" />
</list>
</value>
</entry>
<entry key="build_daemon">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build_daemon-0.2.3/lib" />
</list>
</value>
</entry>
<entry key="build_resolvers">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build_resolvers-0.2.3/lib" />
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build_resolvers-1.0.0/lib" />
</list>
</value>
</entry>
<entry key="build_runner">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build_runner-1.2.3/lib" />
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build_runner-1.2.5/lib" />
</list>
</value>
</entry>
<entry key="build_runner_core">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build_runner_core-2.0.1/lib" />
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build_runner_core-2.0.2/lib" />
</list>
</value>
</entry>
<entry key="build_test">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build_test-0.10.6/lib" />
</list>
</value>
</entry>
<entry key="built_collection">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/built_collection-4.1.0/lib" />
</list>
</value>
</entry>
<entry key="built_value">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/built_value-6.3.0/lib" />
</list>
</value>
</entry>
<entry key="built_value_generator">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/built_value_generator-6.3.0/lib" />
</list>
</value>
</entry>
<entry key="charcode">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/charcode-1.1.2/lib" />
</list>
</value>
</entry>
<entry key="code_builder">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/code_builder-3.2.0/lib" />
</list>
</value>
</entry>
<entry key="collection">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/collection-1.14.11/lib" />
</list>
</value>
</entry>
<entry key="convert">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/convert-2.1.1/lib" />
</list>
</value>
</entry>
<entry key="crypto">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/crypto-2.0.6/lib" />
</list>
</value>
</entry>
<entry key="csslib">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/csslib-0.14.6/lib" />
</list>
</value>
</entry>
<entry key="dart_style">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/dart_style-1.2.3/lib" />
</list>
</value>
</entry>
<entry key="fixnum">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/fixnum-0.10.9/lib" />
</list>
</value>
</entry>
<entry key="front_end">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/front_end-0.1.9+1/lib" />
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/front_end-0.1.10/lib" />
</list>
</value>
</entry>
<entry key="glob">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/glob-1.1.7/lib" />
</list>
</value>
</entry>
<entry key="graphs">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/graphs-0.2.0/lib" />
</list>
</value>
</entry>
<entry key="html">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/html-0.13.3+3/lib" />
</list>
</value>
</entry>
<entry key="http">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/http-0.12.0+1/lib" />
</list>
</value>
</entry>
<entry key="http_multi_server">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/http_multi_server-2.0.5/lib" />
</list>
</value>
</entry>
<entry key="http_parser">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/http_parser-3.1.3/lib" />
</list>
</value>
</entry>
<entry key="io">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/io-0.3.3/lib" />
</list>
</value>
</entry>
<entry key="js">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/js-0.6.1+1/lib" />
</list>
</value>
</entry>
<entry key="json_annotation">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/json_annotation-2.0.0/lib" />
</list>
</value>
</entry>
<entry key="json_rpc_2">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/json_rpc_2-2.0.9/lib" />
</list>
</value>
</entry>
<entry key="kernel">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/kernel-0.3.9+1/lib" />
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/kernel-0.3.10/lib" />
</list>
</value>
</entry>
<entry key="logging">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/logging-0.11.3+2/lib" />
</list>
</value>
</entry>
<entry key="matcher">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.3+1/lib" />
</list>
</value>
</entry>
<entry key="meta">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/meta-1.1.7/lib" />
</list>
</value>
</entry>
<entry key="mime">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/mime-0.9.6+2/lib" />
</list>
</value>
</entry>
<entry key="mockito">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/mockito-4.0.0/lib" />
</list>
</value>
</entry>
<entry key="multi_server_socket">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/multi_server_socket-1.0.2/lib" />
</list>
</value>
</entry>
<entry key="node_preamble">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/node_preamble-1.4.4/lib" />
</list>
</value>
</entry>
<entry key="package_config">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/package_config-1.0.5/lib" />
</list>
</value>
</entry>
<entry key="package_resolver">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/package_resolver-1.0.6/lib" />
</list>
</value>
</entry>
<entry key="path">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/path-1.6.2/lib" />
</list>
</value>
</entry>
<entry key="pedantic">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/pedantic-1.4.0/lib" />
</list>
</value>
</entry>
<entry key="plugin">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/plugin-0.2.0+3/lib" />
</list>
</value>
</entry>
<entry key="pool">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/pool-1.4.0/lib" />
</list>
</value>
</entry>
<entry key="pub_semver">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/pub_semver-1.4.2/lib" />
</list>
</value>
</entry>
<entry key="pubspec_parse">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/pubspec_parse-0.1.4/lib" />
</list>
</value>
</entry>
<entry key="quiver">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/quiver-2.0.1/lib" />
</list>
</value>
</entry>
<entry key="recase">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/recase-2.0.1/lib" />
</list>
</value>
</entry>
<entry key="shelf">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/shelf-0.7.4/lib" />
</list>
</value>
</entry>
<entry key="shelf_packages_handler">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/shelf_packages_handler-1.0.4/lib" />
</list>
</value>
</entry>
<entry key="shelf_static">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/shelf_static-0.2.8/lib" />
</list>
</value>
</entry>
<entry key="shelf_web_socket">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-0.2.2+4/lib" />
</list>
</value>
</entry>
<entry key="source_gen">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_gen-0.9.4+1/lib" />
</list>
</value>
</entry>
<entry key="source_map_stack_trace">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_map_stack_trace-1.1.5/lib" />
</list>
</value>
</entry>
<entry key="source_maps">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_maps-0.10.8/lib" />
</list>
</value>
</entry>
<entry key="source_span">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_span-1.5.4/lib" />
</list>
</value>
</entry>
<entry key="stack_trace">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.9.3/lib" />
</list>
</value>
</entry>
<entry key="stream_channel">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stream_channel-1.6.8/lib" />
</list>
</value>
</entry>
<entry key="stream_transform">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stream_transform-0.0.14+1/lib" />
</list>
</value>
</entry>
<entry key="string_scanner">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.0.4/lib" />
</list>
</value>
</entry>
<entry key="term_glyph">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.1.0/lib" />
</list>
</value>
</entry>
<entry key="test">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/test-1.5.3/lib" />
</list>
</value>
</entry>
<entry key="test_api">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/test_api-0.2.2/lib" />
</list>
</value>
</entry>
<entry key="test_core">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/test_core-0.2.1+1/lib" />
</list>
</value>
</entry>
<entry key="timing">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/timing-0.1.1+1/lib" />
</list>
</value>
</entry>
<entry key="typed_data">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/typed_data-1.1.6/lib" />
</list>
</value>
</entry>
<entry key="utf">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/utf-0.9.0+5/lib" />
</list>
</value>
</entry>
<entry key="vm_service_client">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/vm_service_client-0.2.6/lib" />
</list>
</value>
</entry>
<entry key="watcher">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/watcher-0.9.7+10/lib" />
</list>
</value>
</entry>
<entry key="web_socket_channel">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-1.0.9/lib" />
</list>
</value>
</entry>
<entry key="yaml">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/yaml-2.1.15/lib" />
</list>
</value>
</entry>
</option>
</properties>
<CLASSES>
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/analyzer-0.34.3/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/analyzer-0.35.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/analyzer_plugin-0.0.1-alpha.6/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/args-1.5.1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/async-2.0.8/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/boolean_selector-1.0.4/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build-1.1.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build-1.1.1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build_config-0.3.1+4/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build_daemon-0.2.3/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build_resolvers-0.2.3/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build_resolvers-1.0.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build_runner-1.2.3/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build_runner-1.2.5/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build_runner_core-2.0.1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build_runner_core-2.0.2/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/build_test-0.10.6/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/built_collection-4.1.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/built_value-6.3.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/built_value_generator-6.3.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/charcode-1.1.2/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/code_builder-3.2.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/collection-1.14.11/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/convert-2.1.1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/crypto-2.0.6/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/csslib-0.14.6/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/dart_style-1.2.3/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/fixnum-0.10.9/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/front_end-0.1.10/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/front_end-0.1.9+1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/glob-1.1.7/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/graphs-0.2.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/html-0.13.3+3/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/http-0.12.0+1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/http_multi_server-2.0.5/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/http_parser-3.1.3/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/io-0.3.3/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/js-0.6.1+1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/json_annotation-2.0.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/json_rpc_2-2.0.9/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/kernel-0.3.10/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/kernel-0.3.9+1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/logging-0.11.3+2/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.3+1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/meta-1.1.7/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/mime-0.9.6+2/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/mockito-4.0.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/multi_server_socket-1.0.2/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/node_preamble-1.4.4/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/package_config-1.0.5/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/package_resolver-1.0.6/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/path-1.6.2/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/pedantic-1.4.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/plugin-0.2.0+3/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/pool-1.4.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/pub_semver-1.4.2/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/pubspec_parse-0.1.4/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/quiver-2.0.1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/recase-2.0.1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/shelf-0.7.4/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/shelf_packages_handler-1.0.4/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/shelf_static-0.2.8/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-0.2.2+4/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_gen-0.9.4+1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_map_stack_trace-1.1.5/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_maps-0.10.8/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_span-1.5.4/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.9.3/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stream_channel-1.6.8/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stream_transform-0.0.14+1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.0.4/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.1.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/test-1.5.3/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/test_api-0.2.2/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/test_core-0.2.1+1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/timing-0.1.1+1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/typed_data-1.1.6/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/utf-0.9.0+5/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/vm_service_client-0.2.6/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/watcher-0.9.7+10/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-1.0.9/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/yaml-2.1.15/lib" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@ -0,0 +1,27 @@
<component name="libraryTable">
<library name="Dart SDK">
<CLASSES>
<root url="file:///opt/dart-sdk/lib/async" />
<root url="file:///opt/dart-sdk/lib/cli" />
<root url="file:///opt/dart-sdk/lib/collection" />
<root url="file:///opt/dart-sdk/lib/convert" />
<root url="file:///opt/dart-sdk/lib/core" />
<root url="file:///opt/dart-sdk/lib/developer" />
<root url="file:///opt/dart-sdk/lib/html" />
<root url="file:///opt/dart-sdk/lib/indexed_db" />
<root url="file:///opt/dart-sdk/lib/io" />
<root url="file:///opt/dart-sdk/lib/isolate" />
<root url="file:///opt/dart-sdk/lib/js" />
<root url="file:///opt/dart-sdk/lib/js_util" />
<root url="file:///opt/dart-sdk/lib/math" />
<root url="file:///opt/dart-sdk/lib/mirrors" />
<root url="file:///opt/dart-sdk/lib/svg" />
<root url="file:///opt/dart-sdk/lib/typed_data" />
<root url="file:///opt/dart-sdk/lib/web_audio" />
<root url="file:///opt/dart-sdk/lib/web_gl" />
<root url="file:///opt/dart-sdk/lib/web_sql" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

6
.idea/misc.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

10
.idea/modules.xml Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/example/example.iml" filepath="$PROJECT_DIR$/example/example.iml" />
<module fileurl="file://$PROJECT_DIR$/sally/sally.iml" filepath="$PROJECT_DIR$/sally/sally.iml" />
<module fileurl="file://$PROJECT_DIR$/sally_generator/sally_generator.iml" filepath="$PROJECT_DIR$/sally_generator/sally_generator.iml" />
</modules>
</component>
</project>

48
.travis.yml Normal file
View File

@ -0,0 +1,48 @@
# Created with package:mono_repo v1.2.1
language: dart
jobs:
include:
- stage: analyze
name: "SDK: stable - DIR: sally - TASKS: dartanalyzer ."
script: ./tool/travis.sh dartanalyzer
env: PKG="sally"
dart: stable
- stage: analyze
name: "SDK: stable - DIR: sally - TASKS: dartfmt -n --set-exit-if-changed ."
script: ./tool/travis.sh dartfmt
env: PKG="sally"
dart: stable
- stage: unit_test
name: "SDK: stable - DIR: sally - TASKS: pub run test"
script: ./tool/travis.sh test
env: PKG="sally"
dart: stable
- stage: analyze
name: "SDK: stable - DIR: sally_generator - TASKS: dartanalyzer ."
script: ./tool/travis.sh dartanalyzer
env: PKG="sally_generator"
dart: stable
- stage: analyze
name: "SDK: stable - DIR: sally_generator - TASKS: dartfmt -n --set-exit-if-changed ."
script: ./tool/travis.sh dartfmt
env: PKG="sally_generator"
dart: stable
- stage: unit_test
name: "SDK: stable - DIR: sally_generator - TASKS: pub run test"
script: ./tool/travis.sh test
env: PKG="sally_generator"
dart: stable
stages:
- analyze
- unit_test
# Only building master means that we don't run two builds for each pull request.
branches:
only:
- master
cache:
directories:
- "$HOME/.pub-cache"

3
example/CHANGELOG.md Normal file
View File

@ -0,0 +1,3 @@
## 1.0.0
- Initial version, created by Stagehand

4
example/README.md Normal file
View File

@ -0,0 +1,4 @@
A sample command-line application.
Created from templates made available by Stagehand under a BSD-style
[license](https://github.com/dart-lang/stagehand/blob/master/LICENSE).

14
example/example.iml Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/.pub" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Dart SDK" level="project" />
<orderEntry type="library" name="Dart Packages" level="project" />
</component>
</module>

26
example/lib/example.dart Normal file
View File

@ -0,0 +1,26 @@
import 'package:sally/sally.dart';
import 'package:sally/src/queries/table_structure.dart';
part 'example.g.dart';
class Products extends Table {
IntColumn get id => integer().named("products_id").autoIncrement()();
TextColumn get name => text()();
}
class Users extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get name => text().withLength(min: 6, max: 32)();
}
@UseData(tables: [Products, Users])
class ShopDb extends SallyDb with _$ShopDbMixin {
Future<List<User>> allUsers() => users.select().get();
Future<User> userByName(String name) => users.select().where((u) => u.name.equals(name)).single();
}

View File

@ -0,0 +1,40 @@
part of 'example.dart';
class _$ShopDbMixin implements QueryExecutor {
final StructuredUsersTable users = StructuredUsersTable();
Future<List<Map<String, dynamic>>> executeQuery(String sql, [dynamic params]) {
return null;
}
}
class StructuredUsersTable extends Users with TableStructure<Users, User> {
@override
final StructuredIntColumn id = StructuredIntColumn("id");
@override
final StructuredTextColumn name = StructuredTextColumn("name");
@override
String get sqlTableName => "users";
@override
User parse(Map<String, dynamic> result) {
return User(result["id"], result["name"]);
}
@override
Users get asTable => this;
}
class User {
final int id;
final String name;
User(this.id, this.name);
}

19
example/pubspec.yaml Normal file
View File

@ -0,0 +1,19 @@
name: example
description: A sample command-line application.
# version: 1.0.0
# homepage: https://www.example.com
# author: simon <email@example.com>
environment:
sdk: '>=2.1.0 <3.0.0'
dependencies:
sally:
path: ../sally
dev_dependencies:
sally_generator:
path: ../sally_generator
build_runner:
pedantic: ^1.0.0
test: ^1.0.0

79
sally/.gitignore vendored
View File

@ -26,82 +26,5 @@ doc/api/
*.js.map
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### Intellij Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr
# Sonarlint plugin
.idea/sonarlint
.idea/**/*
# End of https://www.gitignore.io/api/dart,intellij

3
sally/CHANGELOG.md Normal file
View File

@ -0,0 +1,3 @@
## 1.0.0
- Initial version, created by Stagehand

22
sally/README.md Normal file
View File

@ -0,0 +1,22 @@
A library for Dart developers.
Created from templates made available by Stagehand under a BSD-style
[license](https://github.com/dart-lang/stagehand/blob/master/LICENSE).
## Usage
A simple usage example:
```dart
import 'package:sally/sally.dart';
main() {
var awesome = new Awesome();
}
```
## Features and bugs
Please file feature requests and bugs at the [issue tracker][tracker].
[tracker]: http://example.com/issues/replaceme

5
sally/lib/sally.dart Normal file
View File

@ -0,0 +1,5 @@
library sally;
export 'package:sally/src/dsl/table.dart';
export 'package:sally/src/dsl/columns.dart';
export 'package:sally/src/database.dart';

View File

@ -0,0 +1,12 @@
class UseData {
final List<Type> tables;
final int schemaVersion;
const UseData({this.tables, this.schemaVersion = 1});
}
abstract class QueryExecutor {
Future<List<Map<String, dynamic>>> executeQuery(String sql, [dynamic params]);
}
abstract class SallyDb {}

View File

@ -0,0 +1,70 @@
// todo more datatypes (at least DateTime and Binary blobs)!
// todo nullability
import 'package:sally/src/queries/predicates/predicate.dart';
class Column<T> {
Predicate equals(T compare) => null;
}
class IntColumn extends Column<int> {
Predicate isBiggerThan(int i) => null;
Predicate isSmallerThan(int i) => null;
}
class BoolColumn extends Column<bool> {
Predicate isTrue() => null;
Predicate isFalse() => null;
}
class TextColumn extends Column<String> {
Predicate like(String regex) => null;
}
class ColumnBuilder<T> {
/// By default, the field name will be used as the column name, e.g.
/// `IntColumn get id = integer()` will have "id" as its associated name. To change
/// this, use `IntColumn get id = integer((c) => c.named('user_id'))`.
ColumnBuilder<T> named(String name) => this;
ColumnBuilder<T> primaryKey() => this;
// ColumnBuilder<T> references<Table>(Column<T> extractor(Table table)) => this;
Column<T> call() => null;
}
class IntColumnBuilder extends ColumnBuilder<int> {
@override
IntColumnBuilder named(String name) => this;
@override
IntColumnBuilder primaryKey() => this;
// @override
// IntColumnBuilder references<Table>(Column<int> extractor(Table table)) => this;
@override
IntColumn call() => null;
IntColumnBuilder autoIncrement() => this;
}
class BoolColumnBuilder extends ColumnBuilder<bool> {
@override
BoolColumnBuilder named(String name) => this;
@override
BoolColumnBuilder primaryKey() => this;
// @override
// BoolColumnBuilder references<Table>(Column<bool> extractor(Table table)) => this;
@override
BoolColumn call() => null;
}
class TextColumnBuilder extends ColumnBuilder<String> {
@override
TextColumnBuilder named(String name) => this;
@override
TextColumnBuilder primaryKey() => this;
// @override
// TextColumnBuilder references<Table>(Column<String> extractor(Table table)) => this;
@override
TextColumn call() => null;
TextColumnBuilder withLength({int min, int max}) => this;
}

View File

@ -0,0 +1,22 @@
import 'package:meta/meta.dart';
import 'package:sally/sally.dart';
abstract class Table {
const Table();
@visibleForOverriding
String get tableName => null;
@visibleForOverriding
// todo allow custom primary key
PrimaryKey get primaryKey => null;
@protected
IntColumnBuilder integer() => null;
@protected
TextColumnBuilder text() => null;
@protected
BoolColumnBuilder boolean() => null;
}
class PrimaryKey {}

View File

@ -0,0 +1,10 @@
export 'package:sally/src/queries/generation_context.dart';
export 'package:sally/src/queries/expressions/limit.dart';
export 'package:sally/src/queries/expressions/variable.dart';
export 'package:sally/src/queries/expressions/where.dart';
import 'package:sally/src/queries/expressions/expressions.dart';
abstract class SqlExpression {
void writeInto(GenerationContext context);
}

View File

@ -0,0 +1,17 @@
import 'package:sally/src/queries/expressions/expressions.dart';
import 'package:sally/src/queries/generation_context.dart';
class LimitExpression extends SqlExpression {
final int amount;
final int offset;
LimitExpression(this.amount, this.offset);
@override
void writeInto(GenerationContext context) {
if (offset != null)
context.buffer.write('LIMIT $amount, $offset ');
else
context.buffer.write('LIMIT $amount ');
}
}

View File

@ -0,0 +1,15 @@
import 'package:sally/src/queries/expressions/expressions.dart';
import 'package:sally/src/queries/generation_context.dart';
class Variable extends SqlExpression {
final dynamic value;
Variable(this.value);
@override
void writeInto(GenerationContext context) {
context.addBoundVariable(value);
context.buffer.write('? ');
}
}

View File

@ -0,0 +1,15 @@
import 'package:sally/src/queries/expressions/expressions.dart';
import 'package:sally/src/queries/generation_context.dart';
import 'package:sally/src/queries/predicates/predicate.dart';
class WhereExpression extends SqlExpression {
final Predicate predicate;
WhereExpression(this.predicate);
@override
void writeInto(GenerationContext context) {
context.buffer.write("WHERE ");
predicate.writeInto(context);
}
}

View File

@ -0,0 +1,8 @@
class GenerationContext {
StringBuffer buffer = StringBuffer();
List<dynamic> boundVariables = List();
void addBoundVariable(dynamic data) {
boundVariables.add(data);
}
}

View File

@ -0,0 +1,44 @@
import 'package:sally/src/queries/generation_context.dart';
import 'package:sally/src/queries/predicates/predicate.dart';
class NotPredicate extends Predicate {
final Predicate inner;
NotPredicate(this.inner);
@override
void writeInto(GenerationContext context) {
context.buffer.write("NOT ");
inner.writeInto(context);
}
}
class OrPredicate extends Predicate {
final Predicate a, b;
OrPredicate(this.a, this.b);
@override
void writeInto(GenerationContext context) {
context.buffer.write('(');
a.writeInto(context);
context.buffer.write(') OR ( ');
b.writeInto(context);
context.buffer.write(') ');
}
}
class AndPredicate extends Predicate {
final Predicate a, b;
AndPredicate(this.a, this.b);
@override
void writeInto(GenerationContext context) {
context.buffer.write('(');
a.writeInto(context);
context.buffer.write(') AND (');
b.writeInto(context);
context.buffer.write(') ');
}
}

View File

@ -0,0 +1,27 @@
import 'package:sally/src/queries/expressions/expressions.dart';
import 'package:sally/src/queries/generation_context.dart';
import 'package:sally/src/queries/predicates/predicate.dart';
enum ComparisonOperator { less, less_or_equal, more, more_or_equal }
class NumberComparisonPredicate extends Predicate {
static const Map<ComparisonOperator, String> _operators = {
ComparisonOperator.less: '< ',
ComparisonOperator.less_or_equal: '<= ',
ComparisonOperator.more: '> ',
ComparisonOperator.more_or_equal: '>= ',
};
SqlExpression left;
ComparisonOperator operator;
SqlExpression right;
NumberComparisonPredicate(this.left, this.operator, this.right);
@override
void writeInto(GenerationContext context) {
left.writeInto(context);
context.buffer.write(_operators[operator]);
right.writeInto(context);
}
}

View File

@ -0,0 +1,43 @@
export 'package:sally/src/queries/predicates/combining.dart';
export 'package:sally/src/queries/predicates/numbers.dart';
export 'package:sally/src/queries/predicates/text.dart';
import 'package:sally/src/queries/expressions/expressions.dart';
import 'package:sally/src/queries/generation_context.dart';
import 'package:sally/src/queries/predicates/combining.dart';
Predicate not(Predicate p) => p.not();
abstract class Predicate extends SqlExpression {
Predicate not() {
return NotPredicate(this);
}
Predicate and(Predicate other) => AndPredicate(this, other);
Predicate or(Predicate other) => OrPredicate(this, other);
}
class EqualityPredicate extends Predicate {
SqlExpression left;
SqlExpression right;
EqualityPredicate(this.left, this.right);
@override
void writeInto(GenerationContext context) {
left.writeInto(context);
context.buffer.write('= ');
right.writeInto(context);
}
}
class BooleanExpressionPredicate extends Predicate {
SqlExpression expression;
BooleanExpressionPredicate(this.expression);
@override
void writeInto(GenerationContext context) {
expression.writeInto(context);
}
}

View File

@ -0,0 +1,17 @@
import 'package:sally/src/queries/expressions/expressions.dart';
import 'package:sally/src/queries/generation_context.dart';
import 'package:sally/src/queries/predicates/predicate.dart';
class LikePredicate extends Predicate {
SqlExpression target;
SqlExpression regex;
LikePredicate(this.target, this.regex);
@override
void writeInto(GenerationContext context) {
target.writeInto(context);
context.buffer.write('LIKE ');
regex.writeInto(context);
}
}

View File

@ -0,0 +1,71 @@
import 'package:sally/src/queries/expressions/limit.dart';
import 'package:sally/src/queries/expressions/where.dart';
import 'package:sally/src/queries/generation_context.dart';
import 'package:sally/src/queries/predicates/predicate.dart';
import 'package:sally/src/queries/table_structure.dart';
abstract class SqlStatement {
GenerationContext _buildQuery();
}
abstract class StatementForExistingData<Table, Result> extends SqlStatement {
final TableStructure<Table, Result> _table;
StatementForExistingData(this._table);
WhereExpression _where;
LimitExpression _limit;
Future<List<Result>> get() async {
final ctx = _buildQuery();
final sql = ctx.buffer.toString();
final vars = ctx.boundVariables;
final result = await _table.executor.executeQuery(sql, vars);
return result.map(_table.parse).toList();
}
Future<Result> single() async {
// limit to one item, using the existing offset if it exists
_limit = LimitExpression(1, _limit?.offset ?? 0);
return (await get()).single;
}
StatementForExistingData<Table, Result> where(
Predicate extractor(Table tbl)) {
final addedPredicate = extractor(_table.asTable);
if (_where != null) {
// merge existing where expression together with new one by and-ing them
// together.
_where = WhereExpression(_where.predicate.and(addedPredicate));
} else {
_where = WhereExpression(addedPredicate);
}
return this;
}
StatementForExistingData<Table, Result> limit({int amount, int offset}) {
_limit = LimitExpression(amount, offset);
return this;
}
}
class SelectStatement<T, R> extends StatementForExistingData<T, R> {
SelectStatement(TableStructure<T, R> table) : super(table);
@override
GenerationContext _buildQuery() {
GenerationContext context = GenerationContext();
context.buffer.write('SELECT * FROM ');
context.buffer.write(_table.sqlTableName);
context.buffer.write(' ');
if (_where != null) _where.writeInto(context);
if (_limit != null) _limit.writeInto(context);
return context;
}
}

View File

@ -0,0 +1,71 @@
import 'package:sally/sally.dart';
import 'package:sally/src/dsl/columns.dart';
import 'package:sally/src/queries/expressions/expressions.dart';
import 'package:sally/src/queries/expressions/variable.dart';
import 'package:sally/src/queries/generation_context.dart';
import 'package:sally/src/queries/predicates/numbers.dart';
import 'package:sally/src/queries/predicates/predicate.dart';
import 'package:sally/src/queries/predicates/text.dart';
import 'package:sally/src/queries/statements.dart';
abstract class TableStructure<UserSpecifiedTable, ResolvedType> {
QueryExecutor executor;
UserSpecifiedTable get asTable;
String get sqlTableName;
ResolvedType parse(Map<String, dynamic> result);
SelectStatement<UserSpecifiedTable, ResolvedType> select() =>
SelectStatement<UserSpecifiedTable, ResolvedType>(this);
}
class StructuredColumn<T> implements SqlExpression, Column<T> {
final String sqlName;
StructuredColumn(this.sqlName);
@override
void writeInto(GenerationContext context) {
// todo table name lookup, as-expressions etc?
context.buffer.write(sqlName);
context.buffer.write(' ');
}
@override
Predicate equals(T compare) => EqualityPredicate(this, Variable(compare));
}
class StructuredIntColumn extends StructuredColumn<int> implements IntColumn {
StructuredIntColumn(String sqlName) : super(sqlName);
@override
Predicate isBiggerThan(int i) =>
NumberComparisonPredicate(this, ComparisonOperator.more, Variable(i));
@override
Predicate isSmallerThan(int i) =>
NumberComparisonPredicate(this, ComparisonOperator.less, Variable(i));
}
class StructuredBoolColumn extends StructuredColumn<bool>
implements BoolColumn {
StructuredBoolColumn(String sqlName) : super(sqlName);
@override
Predicate isFalse() {
return not(isTrue());
}
@override
Predicate isTrue() {
return BooleanExpressionPredicate(this);
}
}
class StructuredTextColumn extends StructuredColumn<String>
implements TextColumn {
StructuredTextColumn(String sqlName) : super(sqlName);
@override
Predicate like(String regex) => LikePredicate(this, Variable(regex));
}

9
sally/mono_pkg.yaml Normal file
View File

@ -0,0 +1,9 @@
dart:
- stable
stages:
- analyze:
- dartanalyzer
- dartfmt
- unit_test:
- test

15
sally/pubspec.yaml Normal file
View File

@ -0,0 +1,15 @@
name: sally
description: A starting point for Dart libraries or applications.
# version: 1.0.0
# homepage: https://www.example.com
# author: Simon Binder <email@example.com>
environment:
sdk: '>=2.1.0 <3.0.0'
dependencies:
meta: '>= 1.0.0 <2.0.0'
dev_dependencies:
mockito: ^4.0.0
test: ^1.0.0

15
sally/sally.iml Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/.pub" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Dart SDK" level="project" />
<orderEntry type="library" name="Dart Packages" level="project" />
</component>
</module>

View File

@ -0,0 +1,80 @@
import 'package:sally/sally.dart';
import 'package:sally/src/queries/predicates/predicate.dart';
import 'package:sally/src/queries/table_structure.dart';
import 'package:test_api/test_api.dart';
import 'package:mockito/mockito.dart';
class MockExecutor extends Mock implements QueryExecutor {}
class Users extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get name => text().withLength(min: 6, max: 32)();
BoolColumn get isAwesome => boolean()();
}
// Example tables and data classes, these would be generated by sally_generator
// in a real project
class UserDataObject {
final int id;
final String name;
UserDataObject(this.id, this.name);
}
class GeneratedUsersTable extends Users
with TableStructure<Users, UserDataObject> {
@override
Users get asTable => this;
@override
UserDataObject parse(Map<String, dynamic> result) {
return UserDataObject(result["id"], result["name"]);
}
@override
String get sqlTableName => "users";
IntColumn id = StructuredIntColumn("id");
TextColumn name = StructuredTextColumn("name");
BoolColumn isAwesome = StructuredBoolColumn("is_awesome");
}
void main() {
GeneratedUsersTable users;
MockExecutor executor;
setUp(() {
users = GeneratedUsersTable();
executor = MockExecutor();
users.executor = executor;
when(executor.executeQuery(any, any)).thenAnswer((_) => Future.value([]));
});
group("Generates SELECT statements", () {
test("generates simple statements", () {
users.select().get();
verify(executor.executeQuery("SELECT * FROM users ", any));
});
test("generates limit statements", () {
users.select().limit(amount: 10).get();
verify(executor.executeQuery("SELECT * FROM users LIMIT 10 ", any));
});
test("generates like expressions", () {
users.select().where((u) => u.name.like("Dash%")).get();
verify(executor
.executeQuery("SELECT * FROM users WHERE name LIKE ? ", ["Dash%"]));
});
test("generates complex predicates", () {
users
.select()
.where((u) => not(u.name.equals("Dash")).and(u.id.isBiggerThan(12)))
.get();
verify(executor.executeQuery(
"SELECT * FROM users WHERE (NOT name = ? ) AND (id > ? ) ",
["Dash", 12]));
});
});
}

View File

@ -0,0 +1,3 @@
## 1.0.0
- Initial version, created by Stagehand

22
sally_generator/README.md Normal file
View File

@ -0,0 +1,22 @@
A library for Dart developers.
Created from templates made available by Stagehand under a BSD-style
[license](https://github.com/dart-lang/stagehand/blob/master/LICENSE).
## Usage
A simple usage example:
```dart
import 'package:sally_generator/sally_generator.dart';
main() {
var awesome = new Awesome();
}
```
## Features and bugs
Please file feature requests and bugs at the [issue tracker][tracker].
[tracker]: http://example.com/issues/replaceme

View File

@ -0,0 +1,8 @@
#builders:
# sally_generator:
# import: "package:sally_generator/generator.dart"
# builder_factories: ["sallyBuilder"]
# build_extensions: {".dart": [".sally.g.part"]}
# auto_apply: dependents
# build_to: cache
# applies_builders: ["source_gen|combining_builder"]

View File

@ -0,0 +1,6 @@
import 'package:build/build.dart';
import 'package:source_gen/source_gen.dart';
import 'package:sally_generator/src/sally_generator.dart';
Builder sallyBuilder(BuilderOptions _) =>
new SharedPartBuilder([SallyGenerator()], "sally");

View File

@ -0,0 +1,18 @@
import 'package:analyzer/dart/element/element.dart';
class SallyError {
final bool critical;
final String message;
final Element affectedElement;
SallyError(
{this.critical = false, this.message, this.affectedElement = null});
}
class ErrorStore {
final List<SallyError> errors = [];
void add(SallyError error) => errors.add(error);
bool get hasCriticalError => errors.any((e) => e.critical);
}

View File

@ -0,0 +1,80 @@
import 'package:built_value/built_value.dart';
part 'specified_column.g.dart';
enum ColumnType { integer, text, boolean }
abstract class ColumnName implements Built<ColumnName, ColumnNameBuilder> {
/// A column name is implicit if it has been looked up with the associated
/// field name in the table class. It's explicit if `.named()` was called in
/// the column builder.
bool get implicit;
String get name;
ColumnName._();
factory ColumnName([updates(ColumnNameBuilder b)]) = _$ColumnName;
factory ColumnName.implicitly(String name) => ColumnName((b) => b
..implicit = true
..name = name);
factory ColumnName.explicitly(String name) => ColumnName((b) => b
..implicit = false
..name = name);
}
class SpecifiedColumn {
final ColumnType type;
final ColumnName name;
bool get hasAI => features.any((f) => f is AutoIncrement);
/// Whether this column has been declared as the primary key via the
/// column builder. The `primaryKey` field in the table class is unrelated to
/// this.
final bool declaredAsPrimaryKey;
final List<ColumnFeature> features;
const SpecifiedColumn(
{this.type,
this.name,
this.declaredAsPrimaryKey = false,
this.features = const []});
}
abstract class ColumnFeature {
const ColumnFeature();
}
class AutoIncrement extends ColumnFeature {
static const AutoIncrement _instance = AutoIncrement._();
const AutoIncrement._();
factory AutoIncrement() => _instance;
@override
bool operator ==(other) => other is AutoIncrement;
}
abstract class LimitingTextLength extends ColumnFeature
implements Built<LimitingTextLength, LimitingTextLengthBuilder> {
@nullable
int get minLength;
@nullable
int get maxLength;
LimitingTextLength._();
factory LimitingTextLength(void updates(LimitingTextLengthBuilder b)) =
_$LimitingTextLength;
factory LimitingTextLength.withLength({int min, int max}) =>
LimitingTextLength((b) => b
..minLength = min
..maxLength = max);
}
class Reference extends ColumnFeature {
final SpecifiedColumn referencedColumn;
const Reference(this.referencedColumn);
}

View File

@ -0,0 +1,185 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'specified_column.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
class _$ColumnName extends ColumnName {
@override
final bool implicit;
@override
final String name;
factory _$ColumnName([void updates(ColumnNameBuilder b)]) =>
(new ColumnNameBuilder()..update(updates)).build();
_$ColumnName._({this.implicit, this.name}) : super._() {
if (implicit == null) {
throw new BuiltValueNullFieldError('ColumnName', 'implicit');
}
if (name == null) {
throw new BuiltValueNullFieldError('ColumnName', 'name');
}
}
@override
ColumnName rebuild(void updates(ColumnNameBuilder b)) =>
(toBuilder()..update(updates)).build();
@override
ColumnNameBuilder toBuilder() => new ColumnNameBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is ColumnName &&
implicit == other.implicit &&
name == other.name;
}
@override
int get hashCode {
return $jf($jc($jc(0, implicit.hashCode), name.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('ColumnName')
..add('implicit', implicit)
..add('name', name))
.toString();
}
}
class ColumnNameBuilder implements Builder<ColumnName, ColumnNameBuilder> {
_$ColumnName _$v;
bool _implicit;
bool get implicit => _$this._implicit;
set implicit(bool implicit) => _$this._implicit = implicit;
String _name;
String get name => _$this._name;
set name(String name) => _$this._name = name;
ColumnNameBuilder();
ColumnNameBuilder get _$this {
if (_$v != null) {
_implicit = _$v.implicit;
_name = _$v.name;
_$v = null;
}
return this;
}
@override
void replace(ColumnName other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$ColumnName;
}
@override
void update(void updates(ColumnNameBuilder b)) {
if (updates != null) updates(this);
}
@override
_$ColumnName build() {
final _$result = _$v ?? new _$ColumnName._(implicit: implicit, name: name);
replace(_$result);
return _$result;
}
}
class _$LimitingTextLength extends LimitingTextLength {
@override
final int minLength;
@override
final int maxLength;
factory _$LimitingTextLength([void updates(LimitingTextLengthBuilder b)]) =>
(new LimitingTextLengthBuilder()..update(updates)).build();
_$LimitingTextLength._({this.minLength, this.maxLength}) : super._();
@override
LimitingTextLength rebuild(void updates(LimitingTextLengthBuilder b)) =>
(toBuilder()..update(updates)).build();
@override
LimitingTextLengthBuilder toBuilder() =>
new LimitingTextLengthBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is LimitingTextLength &&
minLength == other.minLength &&
maxLength == other.maxLength;
}
@override
int get hashCode {
return $jf($jc($jc(0, minLength.hashCode), maxLength.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('LimitingTextLength')
..add('minLength', minLength)
..add('maxLength', maxLength))
.toString();
}
}
class LimitingTextLengthBuilder
implements Builder<LimitingTextLength, LimitingTextLengthBuilder> {
_$LimitingTextLength _$v;
int _minLength;
int get minLength => _$this._minLength;
set minLength(int minLength) => _$this._minLength = minLength;
int _maxLength;
int get maxLength => _$this._maxLength;
set maxLength(int maxLength) => _$this._maxLength = maxLength;
LimitingTextLengthBuilder();
LimitingTextLengthBuilder get _$this {
if (_$v != null) {
_minLength = _$v.minLength;
_maxLength = _$v.maxLength;
_$v = null;
}
return this;
}
@override
void replace(LimitingTextLength other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$LimitingTextLength;
}
@override
void update(void updates(LimitingTextLengthBuilder b)) {
if (updates != null) updates(this);
}
@override
_$LimitingTextLength build() {
final _$result = _$v ??
new _$LimitingTextLength._(minLength: minLength, maxLength: maxLength);
replace(_$result);
return _$result;
}
}
// ignore_for_file: always_put_control_body_on_new_line,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@ -0,0 +1,12 @@
import 'package:sally_generator/src/model/specified_column.dart';
import 'package:analyzer/dart/element/element.dart';
class SpecifiedTable {
final ClassElement fromClass;
final List<SpecifiedColumn> columns;
final String sqlName;
final String dartTypeName;
const SpecifiedTable(
{this.fromClass, this.columns, this.sqlName, this.dartTypeName});
}

View File

@ -0,0 +1,134 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:sally_generator/src/errors.dart';
import 'package:sally_generator/src/model/specified_column.dart';
import 'package:sally_generator/src/parser/parser.dart';
import 'package:sally_generator/src/sally_generator.dart';
const String startInt = "integer";
const String startString = "text";
const String startBool = "boolean";
// todo replace with set literal once dart supports it
final Set<String> starters = [startInt, startString, startBool].toSet();
const String functionNamed = "named";
const String functionPrimaryKey = "primaryKey";
const String functionReferences = "references";
const String functionAutoIncrement = "autoIncrement";
const String functionWithLength = "withLength";
const String errorMessage = "This getter does not create a valid column that "
"can be parsed by sally. Please refer to the readme from sally to see how "
"columns are formed. If you have any questions, feel free to raise an issue.";
class ColumnParser extends ParserBase {
ColumnParser(SallyGenerator generator) : super(generator);
SpecifiedColumn parse(MethodDeclaration getter) {
/*
These getters look like this: ... get id => integer().autoIncrement()();
The last () is a FunctionExpressionInvocation, the entries before that
(here autoIncrement and integer) are MethodInvocations.
We go through each of the method invocations until we hit one that starts
the chain (integer, text, boolean, etc.). From each method in the chain,
we can extract what it means for the column (name, auto increment, PK,
constraints...).
*/
final expr = returnExpressionOfMethod(getter);
if (!(expr is FunctionExpressionInvocation)) {
generator.errors.add(SallyError(
affectedElement: getter.declaredElement,
message: errorMessage,
critical: true,
));
return null;
}
var remainingExpr =
(expr as FunctionExpressionInvocation).function as MethodInvocation;
String foundStartMethod;
String foundExplicitName;
bool wasDeclaredAsPrimaryKey = false;
// todo parse reference
List<ColumnFeature> foundFeatures = [];
while (true) {
final methodName = remainingExpr.methodName.name;
if (starters.contains(methodName)) {
foundStartMethod = methodName;
break;
}
switch (methodName) {
case functionNamed:
if (foundExplicitName != null) {
generator.errors.add(SallyError(
critical: false,
affectedElement: getter.declaredElement,
message:
"You're setting more than one name here, the first will "
"be used"));
}
foundExplicitName =
readStringLiteral(remainingExpr.argumentList.arguments.first, () {
generator.errors.add(SallyError(
critical: false,
affectedElement: getter.declaredElement,
message:
"This table name is cannot be resolved! Please only use "
"a constant string as parameter for .named()."));
});
break;
case functionPrimaryKey:
wasDeclaredAsPrimaryKey = true;
break;
case functionReferences:
break; // todo: parsing this is going to suck
case functionWithLength:
final args = remainingExpr.argumentList;
final minArg = findNamedArgument(args, "min");
final maxArg = findNamedArgument(args, "max");
foundFeatures.add(LimitingTextLength.withLength(
min: readIntLiteral(minArg, () {}),
max: readIntLiteral(maxArg, () {}),
));
break;
case functionAutoIncrement:
wasDeclaredAsPrimaryKey = true;
foundFeatures.add(AutoIncrement());
break;
}
// We're not at a starting method yet, so we need to go deeper!
final inner = (remainingExpr.target) as MethodInvocation;
remainingExpr = inner;
}
ColumnName name;
if (foundExplicitName != null) {
name = ColumnName.explicitly(foundExplicitName);
} else {
name = ColumnName.implicitly(getter.name.name);
}
return SpecifiedColumn(
type: _startMethodToColumnType(foundStartMethod),
name: name,
declaredAsPrimaryKey: wasDeclaredAsPrimaryKey,
features: foundFeatures);
}
ColumnType _startMethodToColumnType(String startMethod) {
return const {
startBool: ColumnType.boolean,
startString: ColumnType.text,
startInt: ColumnType.integer,
}[startMethod];
}
}

View File

@ -0,0 +1,62 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:sally_generator/src/errors.dart';
import 'package:sally_generator/src/model/specified_table.dart';
import 'package:sally_generator/src/sally_generator.dart';
class Parser {
List<SpecifiedTable> specifiedTables;
void init() async {}
}
class ParserBase {
final SallyGenerator generator;
ParserBase(this.generator);
Expression returnExpressionOfMethod(MethodDeclaration method) {
final body = method.body;
if (!(body is ExpressionFunctionBody)) {
generator.errors.add(SallyError(
affectedElement: method.declaredElement,
critical: true,
message:
"This method must have an expression body (use => instead of {return ...})"));
return null;
}
return (method.body as ExpressionFunctionBody).expression;
}
String readStringLiteral(Expression expression, void onError()) {
if (!(expression is StringLiteral)) {
onError();
} else {
String value = (expression as StringLiteral).stringValue;
if (value == null)
onError();
else
return value;
}
return null;
}
int readIntLiteral(Expression expression, void onError()) {
if (!(expression is IntegerLiteral)) {
onError();
return null;
} else {
return (expression as IntegerLiteral).value;
}
}
Expression findNamedArgument(ArgumentList args, String argName) {
final argument = args.arguments.singleWhere(
(e) => e is NamedExpression && e.name.label.name == argName,
orElse: () => null) as NamedExpression;
return argument?.expression;
}
}

View File

@ -0,0 +1,68 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:sally_generator/src/errors.dart';
import 'package:sally_generator/src/model/specified_column.dart';
import 'package:sally_generator/src/model/specified_table.dart';
import 'package:sally_generator/src/parser/parser.dart';
import 'package:sally_generator/src/utils/type_utils.dart';
import 'package:sally_generator/src/sally_generator.dart'; // ignore: implementation_imports
import 'package:recase/recase.dart';
class TableParser extends ParserBase {
TableParser(SallyGenerator generator) : super(generator);
SpecifiedTable parse(ClassElement element) {
String sqlName = _parseTableName(element);
return SpecifiedTable(
fromClass: element,
columns: _parseColumns(element),
sqlName: sqlName,
dartTypeName:
"${element.name}_Data" // TODO better name for generated data classes
);
}
String _parseTableName(ClassElement element) {
final tableNameGetter = element.getGetter("tableName");
if (tableNameGetter == null) {
// class does not override tableName. So just use the dart class name
// instead. Will use placed_orders for a class called PlacedOrders
return ReCase(element.name).snakeCase;
}
// we expect something like get tableName => "myTableName", the getter
// must do nothing more complicated
final tableNameDeclaration =
generator.loadElementDeclaration(tableNameGetter);
final returnExpr = returnExpressionOfMethod(
tableNameDeclaration.node as MethodDeclaration);
String tableName = readStringLiteral(returnExpr, () {
generator.errors.add(SallyError(
critical: true,
message:
"This getter must return a string literal, and do nothing more",
affectedElement: tableNameGetter));
});
return tableName;
}
Iterable<MethodDeclaration> _findColumnGetters(ClassElement element) {
return element.fields
.where((field) => isColumn(field.type) && field.getter != null)
.map((field) {
var node = generator.loadElementDeclaration(field.getter).node;
return node as MethodDeclaration;
});
}
SpecifiedColumn _parseColumn(MethodDeclaration getter) {
return generator.columnParser.parse(getter);
}
List<SpecifiedColumn> _parseColumns(ClassElement element) =>
_findColumnGetters(element).map(_parseColumn).toList();
}

View File

@ -0,0 +1,36 @@
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/src/dart/analysis/results.dart'; // ignore: implementation_imports
import 'package:analyzer/dart/element/element.dart';
import 'package:build/build.dart';
import 'package:sally_generator/src/errors.dart';
import 'package:sally_generator/src/parser/column_parser.dart';
import 'package:sally_generator/src/parser/table_parser.dart';
import 'package:source_gen/source_gen.dart';
class SallyGenerator extends Generator {
Map<String, ParsedLibraryResult> _astForLibs = Map();
ErrorStore errors = ErrorStore();
TableParser tableParser;
ColumnParser columnParser;
ElementDeclarationResult loadElementDeclaration(Element element) {
final result = _astForLibs.putIfAbsent(element.library.name, () {
// ignore: deprecated_member_use
return ParsedLibraryResultImpl.tmp(element.library);
});
return result.getElementDeclaration(element);
}
@override
String generate(LibraryReader library, BuildStep buildStep) {
final testUsers = library.findType("Users");
if (testUsers == null) return "";
TableParser(this).parse(testUsers);
return "";
}
}

View File

@ -0,0 +1,9 @@
import 'package:analyzer/dart/element/type.dart';
bool isFromSally(DartType type) {
return type.element.library.location.components.first.contains("sally");
}
bool isColumn(DartType type) {
return isFromSally(type) && type.name.contains("Column");
}

View File

@ -0,0 +1,9 @@
dart:
- stable
stages:
- analyze:
- dartanalyzer
- dartfmt
- unit_test:
- test

View File

@ -0,0 +1,24 @@
name: sally_generator
description: A starting point for Dart libraries or applications.
# version: 1.0.0
# homepage: https://www.example.com
# author: Simon Binder <email@example.com>
environment:
sdk: '>=2.1.0 <3.0.0'
dependencies:
analyzer: '< 0.35.0'
recase:
built_value:
source_gen:
sally:
path:
../sally
dev_dependencies:
test: ^1.0.0
built_value_generator:
build_runner:
build_config:
build_test: '>=0.10.0 <0.11.0'

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/.pub" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Dart SDK" level="project" />
<orderEntry type="library" name="Dart Packages" level="project" />
</component>
</module>

View File

@ -0,0 +1,103 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:sally_generator/src/model/specified_column.dart';
import 'package:sally_generator/src/parser/column_parser.dart';
import 'package:sally_generator/src/parser/table_parser.dart';
import 'package:sally_generator/src/sally_generator.dart';
import 'package:test_api/test_api.dart';
import 'package:build_test/build_test.dart';
void main() async {
LibraryElement testLib;
SallyGenerator generator;
setUpAll(() async {
testLib = await resolveSource(r'''
library test_parser;
import 'package:sally/sally.dart';
class TableWithCustomName extends Table {
@override
String get tableName => "my-fancy-table"
}
class Users extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get name => text().named("user_name").withLength(min: 6, max: 32)();
TextColumn get onlyMax => text().withLength(max: 100)();
}
class WrongName extends Table {
String constructTableName() {
return "my-table-name";
}
@override
String get tableName => constructTableName();"
}
''', (r) => r.findLibraryByName("test_parser"));
});
setUp(() {
generator = SallyGenerator();
generator.columnParser = ColumnParser(generator);
});
group("SQL table name", () {
test("should parse correctly when valid", () {
expect(
TableParser(generator)
.parse(testLib.getType("TableWithCustomName"))
.sqlName,
equals("my-fancy-table"));
});
test("should use class name if table name is not specified", () {
expect(TableParser(generator).parse(testLib.getType("Users")).sqlName,
equals("users"));
});
test("should not parse for complex methods", () async {
TableParser(generator).parse(testLib.getType("WrongName"));
expect(generator.errors.errors, isNotEmpty);
});
});
group("Columns", () {
test("should use field name if no name has been set explicitely", () {
final table = TableParser(generator).parse(testLib.getType("Users"));
final idColumn =
table.columns.singleWhere((col) => col.name.name == "id");
expect(idColumn.name, equals(ColumnName.implicitly("id")));
});
test("should use explicit name, if it exists", () {
final table = TableParser(generator).parse(testLib.getType("Users"));
final idColumn =
table.columns.singleWhere((col) => col.name.name == "user_name");
expect(idColumn.name, equals(ColumnName.explicitly("user_name")));
});
test("should parse min and max length for text columns", () {
final table = TableParser(generator).parse(testLib.getType("Users"));
final idColumn =
table.columns.singleWhere((col) => col.name.name == "user_name");
expect(idColumn.features,
contains(LimitingTextLength.withLength(min: 6, max: 32)));
});
test("should only parse max length when relevant", () {
final table = TableParser(generator).parse(testLib.getType("Users"));
final idColumn =
table.columns.singleWhere((col) => col.name.name == "onlyMax");
expect(
idColumn.features, contains(LimitingTextLength.withLength(max: 100)));
});
});
}

45
tool/travis.sh Executable file
View File

@ -0,0 +1,45 @@
#!/bin/bash
# Created with package:mono_repo v1.2.1
if [ -z "$PKG" ]; then
echo -e '\033[31mPKG environment variable must be set!\033[0m'
exit 1
fi
if [ "$#" == "0" ]; then
echo -e '\033[31mAt least one task argument must be provided!\033[0m'
exit 1
fi
pushd $PKG
pub upgrade || exit $?
EXIT_CODE=0
while (( "$#" )); do
TASK=$1
case $TASK in
dartanalyzer) echo
echo -e '\033[1mTASK: dartanalyzer\033[22m'
echo -e 'dartanalyzer .'
dartanalyzer . || EXIT_CODE=$?
;;
dartfmt) echo
echo -e '\033[1mTASK: dartfmt\033[22m'
echo -e 'dartfmt -n --set-exit-if-changed .'
dartfmt -n --set-exit-if-changed . || EXIT_CODE=$?
;;
test) echo
echo -e '\033[1mTASK: test\033[22m'
echo -e 'pub run test'
pub run test || EXIT_CODE=$?
;;
*) echo -e "\033[31mNot expecting TASK '${TASK}'. Error!\033[0m"
EXIT_CODE=1
;;
esac
shift
done
exit $EXIT_CODE