Merged from sdk-2.12.x_nnbd
This commit is contained in:
parent
3adf9d62bc
commit
62f2235a6d
228 changed files with 3849 additions and 3305 deletions
|
@ -1,15 +0,0 @@
|
||||||
<?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>
|
|
|
@ -1,421 +0,0 @@
|
||||||
<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.32.4/lib" />
|
|
||||||
</list>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="args">
|
|
||||||
<value>
|
|
||||||
<list>
|
|
||||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/args-1.5.0/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="charcode">
|
|
||||||
<value>
|
|
||||||
<list>
|
|
||||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/charcode-1.1.2/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.0.2/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.4+1/lib" />
|
|
||||||
</list>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="dart2_constant">
|
|
||||||
<value>
|
|
||||||
<list>
|
|
||||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/dart2_constant-1.0.2+dart2/lib" />
|
|
||||||
</list>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="front_end">
|
|
||||||
<value>
|
|
||||||
<list>
|
|
||||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/front_end-0.1.4/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="html">
|
|
||||||
<value>
|
|
||||||
<list>
|
|
||||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/html-0.13.3+2/lib" />
|
|
||||||
</list>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="http">
|
|
||||||
<value>
|
|
||||||
<list>
|
|
||||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/http-0.11.3+17/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="http_server">
|
|
||||||
<value>
|
|
||||||
<list>
|
|
||||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/http_server-0.9.8/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_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.4/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.6/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="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.4/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="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.3.6/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="shelf">
|
|
||||||
<value>
|
|
||||||
<list>
|
|
||||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/shelf-0.7.3+3/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_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.7/lib" />
|
|
||||||
</list>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="source_span">
|
|
||||||
<value>
|
|
||||||
<list>
|
|
||||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_span-1.4.1/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="string_scanner">
|
|
||||||
<value>
|
|
||||||
<list>
|
|
||||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.0.3/lib" />
|
|
||||||
</list>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="term_glyph">
|
|
||||||
<value>
|
|
||||||
<list>
|
|
||||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.0.1/lib" />
|
|
||||||
</list>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="test">
|
|
||||||
<value>
|
|
||||||
<list>
|
|
||||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/test-1.3.0/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.32.4/lib" />
|
|
||||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/args-1.5.0/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/charcode-1.1.2/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.0.2/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.4+1/lib" />
|
|
||||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/dart2_constant-1.0.2+dart2/lib" />
|
|
||||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/front_end-0.1.4/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/html-0.13.3+2/lib" />
|
|
||||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/http-0.11.3+17/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/http_server-0.9.8/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_rpc_2-2.0.9/lib" />
|
|
||||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/kernel-0.3.4/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.6/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/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.4/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/plugin-0.2.0+3/lib" />
|
|
||||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/pool-1.3.6/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/shelf-0.7.3+3/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_map_stack_trace-1.1.5/lib" />
|
|
||||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_maps-0.10.7/lib" />
|
|
||||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_span-1.4.1/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/string_scanner-1.0.3/lib" />
|
|
||||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.0.1/lib" />
|
|
||||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/test-1.3.0/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 />
|
|
||||||
<LIBRARY_FILE />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,8 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/body_parser.iml" filepath="$PROJECT_DIR$/.idea/body_parser.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="main.dart" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application" singleton="true" nameIsGenerated="true">
|
|
||||||
<option name="filePath" value="$PROJECT_DIR$/example/main.dart" />
|
|
||||||
<option name="workingDirectory" value="$PROJECT_DIR$" />
|
|
||||||
<method />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
12
packages/body_parser/AUTHORS.md
Normal file
12
packages/body_parser/AUTHORS.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Primary Authors
|
||||||
|
===============
|
||||||
|
|
||||||
|
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
||||||
|
|
||||||
|
Thomas is the current maintainer of the code base. He has refactored and migrated the
|
||||||
|
code base to support NNBD.
|
||||||
|
|
||||||
|
* __[Tobe O](thosakwe@gmail.com)__
|
||||||
|
|
||||||
|
Tobe has written much of the original code prior to NNBD migration. He has moved on and
|
||||||
|
is no longer involved with the project.
|
|
@ -1,3 +1,6 @@
|
||||||
|
# 2.0.0
|
||||||
|
* Migrated to support Dart SDK 2.12.x NNBD
|
||||||
|
|
||||||
# 1.1.1
|
# 1.1.1
|
||||||
* Dart 2 updates; should fix Angel in Travis.
|
* Dart 2 updates; should fix Angel in Travis.
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
include: package:pedantic/analysis_options.yaml
|
||||||
analyzer:
|
analyzer:
|
||||||
strong-mode:
|
strong-mode:
|
||||||
implicit-casts: false
|
implicit-casts: false
|
|
@ -5,16 +5,16 @@ import 'dart:isolate';
|
||||||
import 'package:http_parser/http_parser.dart';
|
import 'package:http_parser/http_parser.dart';
|
||||||
import 'package:body_parser/body_parser.dart';
|
import 'package:body_parser/body_parser.dart';
|
||||||
|
|
||||||
main() async {
|
void main() async {
|
||||||
var address = '127.0.0.1';
|
var address = '127.0.0.1';
|
||||||
var port = 3000;
|
var port = 3000;
|
||||||
var futures = <Future>[];
|
var futures = <Future>[];
|
||||||
|
|
||||||
for (int i = 1; i < Platform.numberOfProcessors; i++) {
|
for (var i = 1; i < Platform.numberOfProcessors; i++) {
|
||||||
futures.add(Isolate.spawn(start, [address, port, i]));
|
futures.add(Isolate.spawn(start, [address, port, i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future.wait(futures).then((_) {
|
await Future.wait(futures).then((_) {
|
||||||
print('All instances started.');
|
print('All instances started.');
|
||||||
print(
|
print(
|
||||||
'Test with "wrk -t12 -c400 -d30s -s ./example/post.lua http://localhost:3000" or similar');
|
'Test with "wrk -t12 -c400 -d30s -s ./example/post.lua http://localhost:3000" or similar');
|
||||||
|
@ -23,13 +23,13 @@ main() async {
|
||||||
}
|
}
|
||||||
|
|
||||||
void start(List args) {
|
void start(List args) {
|
||||||
var address = new InternetAddress(args[0] as String);
|
var address = InternetAddress(args[0] as String);
|
||||||
int port = 8080;
|
var port = 8080;
|
||||||
if (args[1] is int) {
|
if (args[1] is int) {
|
||||||
args[1];
|
args[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
int id = 0;
|
var id = 0;
|
||||||
if (args[2] is int) {
|
if (args[2] is int) {
|
||||||
args[2];
|
args[2];
|
||||||
}
|
}
|
||||||
|
@ -39,9 +39,9 @@ void start(List args) {
|
||||||
// ignore: deprecated_member_use
|
// ignore: deprecated_member_use
|
||||||
var body = await defaultParseBody(request);
|
var body = await defaultParseBody(request);
|
||||||
request.response
|
request.response
|
||||||
..headers.contentType = new ContentType('application', 'json')
|
..headers.contentType = ContentType('application', 'json')
|
||||||
..write(json.encode(body.body))
|
..write(json.encode(body.body));
|
||||||
..close();
|
await request.response.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
print(
|
print(
|
||||||
|
@ -50,11 +50,11 @@ void start(List args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<BodyParseResult> defaultParseBody(HttpRequest request,
|
Future<BodyParseResult> defaultParseBody(HttpRequest request,
|
||||||
{bool storeOriginalBuffer: false}) {
|
{bool storeOriginalBuffer = false}) {
|
||||||
return parseBodyFromStream(
|
return parseBodyFromStream(
|
||||||
request,
|
request,
|
||||||
request.headers.contentType != null
|
request.headers.contentType != null
|
||||||
? new MediaType.parse(request.headers.contentType.toString())
|
? MediaType.parse(request.headers.contentType.toString())
|
||||||
: null,
|
: null,
|
||||||
request.uri,
|
request.uri,
|
||||||
storeOriginalBuffer: storeOriginalBuffer);
|
storeOriginalBuffer: storeOriginalBuffer);
|
||||||
|
|
|
@ -3,10 +3,10 @@ import 'file_upload_info.dart';
|
||||||
/// A representation of data from an incoming request.
|
/// A representation of data from an incoming request.
|
||||||
abstract class BodyParseResult {
|
abstract class BodyParseResult {
|
||||||
/// The parsed body.
|
/// The parsed body.
|
||||||
Map<String, dynamic> get body;
|
Map<String?, dynamic> get body;
|
||||||
|
|
||||||
/// The parsed query string.
|
/// The parsed query string.
|
||||||
Map<String, dynamic> get query;
|
Map<String?, dynamic> get query;
|
||||||
|
|
||||||
/// All files uploaded within this request.
|
/// All files uploaded within this request.
|
||||||
List<FileUploadInfo> get files;
|
List<FileUploadInfo> get files;
|
||||||
|
@ -14,7 +14,7 @@ abstract class BodyParseResult {
|
||||||
/// The original body bytes sent with this request.
|
/// The original body bytes sent with this request.
|
||||||
///
|
///
|
||||||
/// You must set [storeOriginalBuffer] to `true` to see this.
|
/// You must set [storeOriginalBuffer] to `true` to see this.
|
||||||
List<int> get originalBuffer;
|
List<int>? get originalBuffer;
|
||||||
|
|
||||||
/// If an error was encountered while parsing the body, it will appear here.
|
/// If an error was encountered while parsing the body, it will appear here.
|
||||||
///
|
///
|
||||||
|
@ -24,5 +24,5 @@ abstract class BodyParseResult {
|
||||||
/// If an error was encountered while parsing the body, the call stack will appear here.
|
/// If an error was encountered while parsing the body, the call stack will appear here.
|
||||||
///
|
///
|
||||||
/// Otherwise, this is `null`.
|
/// Otherwise, this is `null`.
|
||||||
StackTrace get stack;
|
StackTrace? get stack;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,6 @@ import 'file_upload_info.dart';
|
||||||
|
|
||||||
List<FileUploadInfo> getFileDataFromChunk(
|
List<FileUploadInfo> getFileDataFromChunk(
|
||||||
String chunk, String boundary, String fileUploadName, Map body) {
|
String chunk, String boundary, String fileUploadName, Map body) {
|
||||||
List<FileUploadInfo> result = [];
|
var result = <FileUploadInfo>[];
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
/// Represents a file uploaded to the server.
|
/// Represents a file uploaded to the server.
|
||||||
class FileUploadInfo {
|
class FileUploadInfo {
|
||||||
/// The MIME type of the uploaded file.
|
/// The MIME type of the uploaded file.
|
||||||
String mimeType;
|
String? mimeType;
|
||||||
|
|
||||||
/// The name of the file field from the request.
|
/// The name of the file field from the request.
|
||||||
String name;
|
String? name;
|
||||||
|
|
||||||
/// The filename of the file.
|
/// The filename of the file.
|
||||||
String filename;
|
String? filename;
|
||||||
|
|
||||||
/// The bytes that make up this file.
|
/// The bytes that make up this file.
|
||||||
List<int> data;
|
List<int> data;
|
||||||
|
|
||||||
FileUploadInfo(
|
FileUploadInfo(
|
||||||
{this.mimeType, this.name, this.filename, this.data: const []}) {}
|
{this.mimeType, this.name, this.filename, this.data = const []});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,22 @@
|
||||||
import 'package:dart2_constant/convert.dart';
|
import 'dart:convert';
|
||||||
|
|
||||||
getValue(String value) {
|
dynamic getValue(String value) {
|
||||||
try {
|
try {
|
||||||
num numValue = num.parse(value);
|
var numValue = num.parse(value);
|
||||||
if (!numValue.isNaN)
|
if (!numValue.isNaN) {
|
||||||
return numValue;
|
return numValue;
|
||||||
else
|
} else {
|
||||||
return value;
|
|
||||||
} on FormatException {
|
|
||||||
if (value.startsWith('[') && value.endsWith(']'))
|
|
||||||
return json.decode(value);
|
|
||||||
else if (value.startsWith('{') && value.endsWith('}'))
|
|
||||||
return json.decode(value);
|
|
||||||
else if (value.trim().toLowerCase() == 'null')
|
|
||||||
return null;
|
|
||||||
else
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
} on FormatException {
|
||||||
|
if (value.startsWith('[') && value.endsWith(']')) {
|
||||||
|
return json.decode(value);
|
||||||
|
} else if (value.startsWith('{') && value.endsWith('}')) {
|
||||||
|
return json.decode(value);
|
||||||
|
} else if (value.trim().toLowerCase() == 'null') {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,19 +3,18 @@ import 'get_value.dart';
|
||||||
/// Parses a URI-encoded string into real data! **Wow!**
|
/// Parses a URI-encoded string into real data! **Wow!**
|
||||||
///
|
///
|
||||||
/// Whichever map you provide will be automatically populated from the urlencoded body string you provide.
|
/// Whichever map you provide will be automatically populated from the urlencoded body string you provide.
|
||||||
buildMapFromUri(Map map, String body) {
|
void buildMapFromUri(Map map, String body) {
|
||||||
RegExp parseArrayRgx = new RegExp(r'^(.+)\[\]$');
|
var parseArrayRgx = RegExp(r'^(.+)\[\]$');
|
||||||
|
|
||||||
for (String keyValuePair in body.split('&')) {
|
for (var keyValuePair in body.split('&')) {
|
||||||
if (keyValuePair.contains('=')) {
|
if (keyValuePair.contains('=')) {
|
||||||
var equals = keyValuePair.indexOf('=');
|
var equals = keyValuePair.indexOf('=');
|
||||||
String key = Uri.decodeQueryComponent(keyValuePair.substring(0, equals));
|
var key = Uri.decodeQueryComponent(keyValuePair.substring(0, equals));
|
||||||
String value =
|
var value = Uri.decodeQueryComponent(keyValuePair.substring(equals + 1));
|
||||||
Uri.decodeQueryComponent(keyValuePair.substring(equals + 1));
|
|
||||||
|
|
||||||
if (parseArrayRgx.hasMatch(key)) {
|
if (parseArrayRgx.hasMatch(key)) {
|
||||||
Match queryMatch = parseArrayRgx.firstMatch(key);
|
Match queryMatch = parseArrayRgx.firstMatch(key)!;
|
||||||
key = queryMatch.group(1);
|
key = queryMatch.group(1)!;
|
||||||
if (!(map[key] is List)) {
|
if (!(map[key] is List)) {
|
||||||
map[key] = [];
|
map[key] = [];
|
||||||
}
|
}
|
||||||
|
@ -23,21 +22,23 @@ buildMapFromUri(Map map, String body) {
|
||||||
map[key].add(getValue(value));
|
map[key].add(getValue(value));
|
||||||
} else if (key.contains('.')) {
|
} else if (key.contains('.')) {
|
||||||
// i.e. map.foo.bar => [map, foo, bar]
|
// i.e. map.foo.bar => [map, foo, bar]
|
||||||
List<String> keys = key.split('.');
|
var keys = key.split('.');
|
||||||
|
|
||||||
Map targetMap = map[keys[0]] != null ? map[keys[0]] as Map : {};
|
var targetMap = map[keys[0]] != null ? map[keys[0]] as Map? : {};
|
||||||
map[keys[0]] = targetMap;
|
map[keys[0]] = targetMap;
|
||||||
for (int i = 1; i < keys.length; i++) {
|
for (var i = 1; i < keys.length; i++) {
|
||||||
if (i < keys.length - 1) {
|
if (i < keys.length - 1) {
|
||||||
targetMap[keys[i]] = targetMap[keys[i]] ?? {};
|
targetMap![keys[i]] = targetMap[keys[i]] ?? {};
|
||||||
targetMap = targetMap[keys[i]] as Map;
|
targetMap = targetMap[keys[i]] as Map?;
|
||||||
} else {
|
} else {
|
||||||
targetMap[keys[i]] = getValue(value);
|
targetMap![keys[i]] = getValue(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
map[key] = getValue(value);
|
map[key] = getValue(value);
|
||||||
} else
|
}
|
||||||
|
} else {
|
||||||
map[Uri.decodeQueryComponent(keyValuePair)] = true;
|
map[Uri.decodeQueryComponent(keyValuePair)] = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:dart2_constant/convert.dart';
|
|
||||||
import 'package:http_parser/http_parser.dart';
|
import 'package:http_parser/http_parser.dart';
|
||||||
import 'package:http_server/http_server.dart';
|
import 'package:http_server/http_server.dart';
|
||||||
import 'package:mime/mime.dart';
|
import 'package:mime/mime.dart';
|
||||||
|
@ -14,11 +14,11 @@ import 'map_from_uri.dart';
|
||||||
/// Forwards to [parseBodyFromStream].
|
/// Forwards to [parseBodyFromStream].
|
||||||
@deprecated
|
@deprecated
|
||||||
Future<BodyParseResult> parseBody(HttpRequest request,
|
Future<BodyParseResult> parseBody(HttpRequest request,
|
||||||
{bool storeOriginalBuffer: false}) {
|
{bool storeOriginalBuffer = false}) {
|
||||||
return parseBodyFromStream(
|
return parseBodyFromStream(
|
||||||
request,
|
request,
|
||||||
request.headers.contentType != null
|
request.headers.contentType != null
|
||||||
? new MediaType.parse(request.headers.contentType.toString())
|
? MediaType.parse(request.headers.contentType.toString())
|
||||||
: null,
|
: null,
|
||||||
request.uri,
|
request.uri,
|
||||||
storeOriginalBuffer: storeOriginalBuffer);
|
storeOriginalBuffer: storeOriginalBuffer);
|
||||||
|
@ -33,13 +33,13 @@ Future<BodyParseResult> parseBody(HttpRequest request,
|
||||||
///
|
///
|
||||||
/// Use [storeOriginalBuffer] to add the original request bytes to the result.
|
/// Use [storeOriginalBuffer] to add the original request bytes to the result.
|
||||||
Future<BodyParseResult> parseBodyFromStream(
|
Future<BodyParseResult> parseBodyFromStream(
|
||||||
Stream<Uint8List> data, MediaType contentType, Uri requestUri,
|
Stream<Uint8List> data, MediaType? contentType, Uri requestUri,
|
||||||
{bool storeOriginalBuffer: false}) async {
|
{bool storeOriginalBuffer = false}) async {
|
||||||
var result = new _BodyParseResultImpl();
|
var result = _BodyParseResultImpl();
|
||||||
|
|
||||||
Future<Uint8List> getBytes() {
|
Future<Uint8List> getBytes() {
|
||||||
return data
|
return data
|
||||||
.fold<BytesBuilder>(new BytesBuilder(copy: false), (a, b) => a..add(b))
|
.fold<BytesBuilder>(BytesBuilder(copy: false), (a, b) => a..add(b))
|
||||||
.then((b) => b.takeBytes());
|
.then((b) => b.takeBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,30 +62,29 @@ Future<BodyParseResult> parseBodyFromStream(
|
||||||
|
|
||||||
if (storeOriginalBuffer) {
|
if (storeOriginalBuffer) {
|
||||||
var bytes = result.originalBuffer = await getBytes();
|
var bytes = result.originalBuffer = await getBytes();
|
||||||
var ctrl = new StreamController<Uint8List>()
|
var ctrl = StreamController<Uint8List>()..add(bytes);
|
||||||
..add(bytes)
|
await ctrl.close();
|
||||||
..close();
|
|
||||||
stream = ctrl.stream;
|
stream = ctrl.stream;
|
||||||
} else {
|
} else {
|
||||||
stream = data;
|
stream = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
var parts = MimeMultipartTransformer(
|
var parts = MimeMultipartTransformer(contentType.parameters['boundary']!)
|
||||||
contentType.parameters['boundary']).bind(stream)
|
.bind(stream)
|
||||||
.map((part) =>
|
.map((part) =>
|
||||||
HttpMultipartFormData.parse(part, defaultEncoding: utf8));
|
HttpMultipartFormData.parse(part, defaultEncoding: utf8));
|
||||||
|
|
||||||
await for (HttpMultipartFormData part in parts) {
|
await for (HttpMultipartFormData part in parts) {
|
||||||
if (part.isBinary ||
|
if (part.isBinary ||
|
||||||
part.contentDisposition.parameters.containsKey("filename")) {
|
part.contentDisposition.parameters.containsKey('filename')) {
|
||||||
BytesBuilder builder = await part.fold(
|
var builder = await part.fold(
|
||||||
new BytesBuilder(copy: false),
|
BytesBuilder(copy: false),
|
||||||
(BytesBuilder b, d) => b
|
(BytesBuilder b, d) => b
|
||||||
..add(d is! String
|
..add(d is! String
|
||||||
? (d as List<int>)
|
? (d as List<int>?)!
|
||||||
: (d as String).codeUnits));
|
: d.codeUnits));
|
||||||
var upload = new FileUploadInfo(
|
var upload = FileUploadInfo(
|
||||||
mimeType: part.contentType.mimeType,
|
mimeType: part.contentType!.mimeType,
|
||||||
name: part.contentDisposition.parameters['name'],
|
name: part.contentDisposition.parameters['name'],
|
||||||
filename:
|
filename:
|
||||||
part.contentDisposition.parameters['filename'] ?? 'file',
|
part.contentDisposition.parameters['filename'] ?? 'file',
|
||||||
|
@ -99,9 +98,9 @@ Future<BodyParseResult> parseBodyFromStream(
|
||||||
}
|
}
|
||||||
} else if (contentType.mimeType == 'application/json') {
|
} else if (contentType.mimeType == 'application/json') {
|
||||||
result.body
|
result.body
|
||||||
.addAll(_foldToStringDynamic(json.decode(await getBody()) as Map));
|
.addAll(_foldToStringDynamic(json.decode(await getBody()) as Map?)!);
|
||||||
} else if (contentType.mimeType == 'application/x-www-form-urlencoded') {
|
} else if (contentType.mimeType == 'application/x-www-form-urlencoded') {
|
||||||
String body = await getBody();
|
var body = await getBody();
|
||||||
buildMapFromUri(result.body, body);
|
buildMapFromUri(result.body, body);
|
||||||
} else if (storeOriginalBuffer == true) {
|
} else if (storeOriginalBuffer == true) {
|
||||||
result.originalBuffer = await getBytes();
|
result.originalBuffer = await getBytes();
|
||||||
|
@ -125,25 +124,25 @@ Future<BodyParseResult> parseBodyFromStream(
|
||||||
|
|
||||||
class _BodyParseResultImpl implements BodyParseResult {
|
class _BodyParseResultImpl implements BodyParseResult {
|
||||||
@override
|
@override
|
||||||
Map<String, dynamic> body = {};
|
Map<String?, dynamic> body = {};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<FileUploadInfo> files = [];
|
List<FileUploadInfo> files = [];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<int> originalBuffer;
|
List<int>? originalBuffer;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, dynamic> query = {};
|
Map<String?, dynamic> query = {};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
var error = null;
|
var error;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
StackTrace stack = null;
|
StackTrace? stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> _foldToStringDynamic(Map map) {
|
Map<String, dynamic>? _foldToStringDynamic(Map? map) {
|
||||||
return map == null
|
return map == null
|
||||||
? null
|
? null
|
||||||
: map.keys.fold<Map<String, dynamic>>(
|
: map.keys.fold<Map<String, dynamic>>(
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
name: body_parser
|
name: body_parser
|
||||||
author: Tobe O <thosakwe@gmail.com>
|
version: 2.0.0
|
||||||
version: 1.1.1
|
|
||||||
description: Parse request bodies and query strings in Dart. Supports JSON, URL-encoded, and multi-part bodies.
|
description: Parse request bodies and query strings in Dart. Supports JSON, URL-encoded, and multi-part bodies.
|
||||||
homepage: https://github.com/angel-dart/body_parser
|
homepage: https://github.com/angel-dart/body_parser
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.10.0 <2.12.0"
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
dart2_constant: ^1.0.0
|
http_parser: ^4.0.0
|
||||||
http_parser: ">=3.1.1 <4.0.0"
|
http_server: ^1.0.0
|
||||||
http_server: ">=0.9.6 <1.0.0"
|
mime: ^1.0.0
|
||||||
mime: ">=0.9.3 <1.0.0"
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
http: ">=0.11.3 <0.12.0"
|
http: ^0.13.0
|
||||||
test: ^1.15.7
|
test: ^1.17.0
|
||||||
|
pedantic: ^1.11.0
|
|
@ -1,54 +1,54 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:body_parser/body_parser.dart';
|
import 'package:body_parser/body_parser.dart';
|
||||||
import 'package:dart2_constant/convert.dart';
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
import 'server_test.dart';
|
import 'server_test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
HttpServer server;
|
HttpServer? server;
|
||||||
String url;
|
String? url;
|
||||||
http.Client client;
|
http.Client? client;
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
server = await HttpServer.bind('127.0.0.1', 0);
|
server = await HttpServer.bind('127.0.0.1', 0);
|
||||||
server.listen((HttpRequest request) async {
|
server!.listen((HttpRequest request) async {
|
||||||
//Server will simply return a JSON representation of the parsed body
|
//Server will simply return a JSON representation of the parsed body
|
||||||
// ignore: deprecated_member_use
|
// ignore: deprecated_member_use
|
||||||
request.response.write(jsonEncodeBody(await parseBody(request)));
|
request.response.write(jsonEncodeBody(await parseBody(request)));
|
||||||
await request.response.close();
|
await request.response.close();
|
||||||
});
|
});
|
||||||
url = 'http://localhost:${server.port}';
|
url = 'http://localhost:${server!.port}';
|
||||||
print('Test server listening on $url');
|
print('Test server listening on $url');
|
||||||
client = http.Client();
|
client = http.Client();
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDown(() async {
|
tearDown(() async {
|
||||||
await server.close(force: true);
|
await server!.close(force: true);
|
||||||
client.close();
|
client!.close();
|
||||||
server = null;
|
server = null;
|
||||||
url = null;
|
url = null;
|
||||||
client = null;
|
client = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('No upload', () async {
|
test('No upload', () async {
|
||||||
String boundary = 'myBoundary';
|
var boundary = 'myBoundary';
|
||||||
Map<String, String> headers = {
|
var headers = <String, String>{
|
||||||
'content-type': 'multipart/form-data; boundary=$boundary'
|
'content-type': 'multipart/form-data; boundary=$boundary'
|
||||||
};
|
};
|
||||||
String postData = '''
|
var postData = '''
|
||||||
--$boundary
|
--$boundary
|
||||||
Content-Disposition: form-data; name="hello"
|
Content-Disposition: form-data; name="hello"
|
||||||
|
|
||||||
world
|
world
|
||||||
--$boundary--
|
--$boundary--
|
||||||
'''
|
'''
|
||||||
.replaceAll("\n", "\r\n");
|
.replaceAll('\n', '\r\n');
|
||||||
|
|
||||||
print(
|
print(
|
||||||
'Form Data: \n${postData.replaceAll("\r", "\\r").replaceAll("\n", "\\n")}');
|
'Form Data: \n${postData.replaceAll("\r", "\\r").replaceAll("\n", "\\n")}');
|
||||||
var response = await client.post(url, headers: headers, body: postData);
|
var response =
|
||||||
|
await client!.post(Uri.parse(url!), headers: headers, body: postData);
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.body}');
|
||||||
var jsons = json.decode(response.body);
|
var jsons = json.decode(response.body);
|
||||||
var files = jsons['files'].map((map) {
|
var files = jsons['files'].map((map) {
|
||||||
|
@ -62,12 +62,12 @@ world
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Single upload', () async {
|
test('Single upload', () async {
|
||||||
String boundary = 'myBoundary';
|
var boundary = 'myBoundary';
|
||||||
Map<String, String> headers = {
|
var headers = <String, String>{
|
||||||
'content-type': ContentType("multipart", "form-data",
|
'content-type': ContentType('multipart', 'form-data',
|
||||||
parameters: {"boundary": boundary}).toString()
|
parameters: {'boundary': boundary}).toString()
|
||||||
};
|
};
|
||||||
String postData = '''
|
var postData = '''
|
||||||
--$boundary
|
--$boundary
|
||||||
Content-Disposition: form-data; name="hello"
|
Content-Disposition: form-data; name="hello"
|
||||||
|
|
||||||
|
@ -79,11 +79,12 @@ Content-Type: application/dart
|
||||||
Hello world
|
Hello world
|
||||||
--$boundary--
|
--$boundary--
|
||||||
'''
|
'''
|
||||||
.replaceAll("\n", "\r\n");
|
.replaceAll('\n', '\r\n');
|
||||||
|
|
||||||
print(
|
print(
|
||||||
'Form Data: \n${postData.replaceAll("\r", "\\r").replaceAll("\n", "\\n")}');
|
'Form Data: \n${postData.replaceAll("\r", "\\r").replaceAll("\n", "\\n")}');
|
||||||
var response = await client.post(url, headers: headers, body: postData);
|
var response =
|
||||||
|
await client!.post(Uri.parse(url!), headers: headers, body: postData);
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.body}');
|
||||||
var jsons = json.decode(response.body);
|
var jsons = json.decode(response.body);
|
||||||
var files = jsons['files'];
|
var files = jsons['files'];
|
||||||
|
@ -96,11 +97,11 @@ Hello world
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Multiple upload', () async {
|
test('Multiple upload', () async {
|
||||||
String boundary = 'myBoundary';
|
var boundary = 'myBoundary';
|
||||||
Map<String, String> headers = {
|
var headers = <String, String>{
|
||||||
'content-type': 'multipart/form-data; boundary=$boundary'
|
'content-type': 'multipart/form-data; boundary=$boundary'
|
||||||
};
|
};
|
||||||
String postData = '''
|
var postData = '''
|
||||||
--$boundary
|
--$boundary
|
||||||
Content-Disposition: form-data; name="json"
|
Content-Disposition: form-data; name="json"
|
||||||
|
|
||||||
|
@ -123,11 +124,12 @@ function main() {
|
||||||
}
|
}
|
||||||
--$boundary--
|
--$boundary--
|
||||||
'''
|
'''
|
||||||
.replaceAll("\n", "\r\n");
|
.replaceAll('\n', '\r\n');
|
||||||
|
|
||||||
print(
|
print(
|
||||||
'Form Data: \n${postData.replaceAll("\r", "\\r").replaceAll("\n", "\\n")}');
|
'Form Data: \n${postData.replaceAll("\r", "\\r").replaceAll("\n", "\\n")}');
|
||||||
var response = await client.post(url, headers: headers, body: postData);
|
var response =
|
||||||
|
await client!.post(Uri.parse(url!), headers: headers, body: postData);
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.body}');
|
||||||
var jsons = json.decode(response.body);
|
var jsons = json.decode(response.body);
|
||||||
var files = jsons['files'];
|
var files = jsons['files'];
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
import 'dart:convert';
|
||||||
import 'dart:io' show HttpRequest, HttpServer;
|
import 'dart:io' show HttpRequest, HttpServer;
|
||||||
|
|
||||||
import 'package:body_parser/body_parser.dart';
|
import 'package:body_parser/body_parser.dart';
|
||||||
import 'package:dart2_constant/convert.dart';
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
@ -27,26 +27,26 @@ String jsonEncodeBody(BodyParseResult result) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
HttpServer server;
|
HttpServer? server;
|
||||||
String url;
|
String? url;
|
||||||
http.Client client;
|
http.Client? client;
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
server = await HttpServer.bind('127.0.0.1', 0);
|
server = await HttpServer.bind('127.0.0.1', 0);
|
||||||
server.listen((HttpRequest request) async {
|
server!.listen((HttpRequest request) async {
|
||||||
//Server will simply return a JSON representation of the parsed body
|
//Server will simply return a JSON representation of the parsed body
|
||||||
request.response.write(
|
request.response.write(
|
||||||
// ignore: deprecated_member_use
|
// ignore: deprecated_member_use
|
||||||
jsonEncodeBody(await parseBody(request, storeOriginalBuffer: true)));
|
jsonEncodeBody(await parseBody(request, storeOriginalBuffer: true)));
|
||||||
await request.response.close();
|
await request.response.close();
|
||||||
});
|
});
|
||||||
url = 'http://localhost:${server.port}';
|
url = 'http://localhost:${server!.port}';
|
||||||
print('Test server listening on $url');
|
print('Test server listening on $url');
|
||||||
client = http.Client();
|
client = http.Client();
|
||||||
});
|
});
|
||||||
tearDown(() async {
|
tearDown(() async {
|
||||||
await server.close(force: true);
|
await server!.close(force: true);
|
||||||
client.close();
|
client!.close();
|
||||||
server = null;
|
server = null;
|
||||||
url = null;
|
url = null;
|
||||||
client = null;
|
client = null;
|
||||||
|
@ -55,7 +55,7 @@ void main() {
|
||||||
group('query string', () {
|
group('query string', () {
|
||||||
test('GET Simple', () async {
|
test('GET Simple', () async {
|
||||||
print('GET $url/?hello=world');
|
print('GET $url/?hello=world');
|
||||||
var response = await client.get('$url/?hello=world');
|
var response = await client!.get(Uri.parse('$url/?hello=world'));
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.body}');
|
||||||
var result = json.decode(response.body);
|
var result = json.decode(response.body);
|
||||||
expect(result['body'], equals({}));
|
expect(result['body'], equals({}));
|
||||||
|
@ -68,7 +68,7 @@ void main() {
|
||||||
var postData =
|
var postData =
|
||||||
'hello=world&nums%5B%5D=1&nums%5B%5D=2.0&nums%5B%5D=${3 - 1}&map.foo.bar=baz';
|
'hello=world&nums%5B%5D=1&nums%5B%5D=2.0&nums%5B%5D=${3 - 1}&map.foo.bar=baz';
|
||||||
print('Body: $postData');
|
print('Body: $postData');
|
||||||
var response = await client.get('$url/?$postData');
|
var response = await client!.get(Uri.parse('$url/?$postData'));
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.body}');
|
||||||
var query = json.decode(response.body)['query'];
|
var query = json.decode(response.body)['query'];
|
||||||
expect(query['hello'], equals('world'));
|
expect(query['hello'], equals('world'));
|
||||||
|
@ -80,7 +80,7 @@ void main() {
|
||||||
test('JWT', () async {
|
test('JWT', () async {
|
||||||
var postData = 'token=$TOKEN';
|
var postData = 'token=$TOKEN';
|
||||||
print('Body: $postData');
|
print('Body: $postData');
|
||||||
var response = await client.get('$url/?$postData');
|
var response = await client!.get(Uri.parse('$url/?$postData'));
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.body}');
|
||||||
var query = json.decode(response.body)['query'];
|
var query = json.decode(response.body)['query'];
|
||||||
expect(query['token'], equals(TOKEN));
|
expect(query['token'], equals(TOKEN));
|
||||||
|
@ -88,13 +88,13 @@ void main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
group('urlencoded', () {
|
group('urlencoded', () {
|
||||||
Map<String, String> headers = {
|
var headers = <String, String>{
|
||||||
'content-type': 'application/x-www-form-urlencoded'
|
'content-type': 'application/x-www-form-urlencoded'
|
||||||
};
|
};
|
||||||
test('POST Simple', () async {
|
test('POST Simple', () async {
|
||||||
print('Body: hello=world');
|
print('Body: hello=world');
|
||||||
var response =
|
var response = await client!.post(Uri.parse(url!),
|
||||||
await client.post(url, headers: headers, body: 'hello=world');
|
headers: headers, body: 'hello=world');
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.body}');
|
||||||
var result = json.decode(response.body);
|
var result = json.decode(response.body);
|
||||||
expect(result['query'], equals({}));
|
expect(result['query'], equals({}));
|
||||||
|
@ -107,7 +107,8 @@ void main() {
|
||||||
test('Post Complex', () async {
|
test('Post Complex', () async {
|
||||||
var postData =
|
var postData =
|
||||||
'hello=world&nums%5B%5D=1&nums%5B%5D=2.0&nums%5B%5D=${3 - 1}&map.foo.bar=baz';
|
'hello=world&nums%5B%5D=1&nums%5B%5D=2.0&nums%5B%5D=${3 - 1}&map.foo.bar=baz';
|
||||||
var response = await client.post(url, headers: headers, body: postData);
|
var response =
|
||||||
|
await client!.post(Uri.parse(url!), headers: headers, body: postData);
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.body}');
|
||||||
var body = json.decode(response.body)['body'];
|
var body = json.decode(response.body)['body'];
|
||||||
expect(body['hello'], equals('world'));
|
expect(body['hello'], equals('world'));
|
||||||
|
@ -118,18 +119,20 @@ void main() {
|
||||||
|
|
||||||
test('JWT', () async {
|
test('JWT', () async {
|
||||||
var postData = 'token=$TOKEN';
|
var postData = 'token=$TOKEN';
|
||||||
var response = await client.post(url, headers: headers, body: postData);
|
var response =
|
||||||
|
await client!.post(Uri.parse(url!), headers: headers, body: postData);
|
||||||
var body = json.decode(response.body)['body'];
|
var body = json.decode(response.body)['body'];
|
||||||
expect(body['token'], equals(TOKEN));
|
expect(body['token'], equals(TOKEN));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
group('json', () {
|
group('json', () {
|
||||||
Map<String, String> headers = {'content-type': 'application/json'};
|
var headers = <String, String>{'content-type': 'application/json'};
|
||||||
test('Post Simple', () async {
|
test('Post Simple', () async {
|
||||||
var postData = json.encode({'hello': 'world'});
|
var postData = json.encode({'hello': 'world'});
|
||||||
print('Body: $postData');
|
print('Body: $postData');
|
||||||
var response = await client.post(url, headers: headers, body: postData);
|
var response =
|
||||||
|
await client!.post(Uri.parse(url!), headers: headers, body: postData);
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.body}');
|
||||||
var result = json.decode(response.body);
|
var result = json.decode(response.body);
|
||||||
expect(result['body'], equals({'hello': 'world'}));
|
expect(result['body'], equals({'hello': 'world'}));
|
||||||
|
@ -147,7 +150,8 @@ void main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
print('Body: $postData');
|
print('Body: $postData');
|
||||||
var response = await client.post(url, headers: headers, body: postData);
|
var response =
|
||||||
|
await client!.post(Uri.parse(url!), headers: headers, body: postData);
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.body}');
|
||||||
var body = json.decode(response.body)['body'];
|
var body = json.decode(response.body)['body'];
|
||||||
expect(body['hello'], equals('world'));
|
expect(body['hello'], equals('world'));
|
||||||
|
|
12
packages/html/AUTHORS.md
Normal file
12
packages/html/AUTHORS.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Primary Authors
|
||||||
|
===============
|
||||||
|
|
||||||
|
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
||||||
|
|
||||||
|
Thomas is the current maintainer of the code base. He has refactored and migrated the
|
||||||
|
code base to support NNBD.
|
||||||
|
|
||||||
|
* __[Tobe O](thosakwe@gmail.com)__
|
||||||
|
|
||||||
|
Tobe has written much of the original code prior to NNBD migration. He has moved on and
|
||||||
|
is no longer involved with the project.
|
|
@ -1,2 +1,5 @@
|
||||||
|
# 3.0.0
|
||||||
|
* Migrated to support Dart SDK 2.12.x NNBD
|
||||||
|
|
||||||
# 2.0.0
|
# 2.0.0
|
||||||
* Angel 2 + Dart 2 updates.
|
* Angel 2 + Dart 2 updates.
|
|
@ -1,6 +1,6 @@
|
||||||
MIT License (MIT)
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2021 dukefirehawk.com
|
Copyright (c) 2017 Tobe O
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
@ -4,8 +4,9 @@ import 'package:angel_html/angel_html.dart';
|
||||||
import 'package:html_builder/elements.dart';
|
import 'package:html_builder/elements.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
main() async {
|
void main() async {
|
||||||
var app = Angel(), http = AngelHttp(app);
|
var app = Angel();
|
||||||
|
var http = AngelHttp(app);
|
||||||
app.logger = Logger('angel_html')
|
app.logger = Logger('angel_html')
|
||||||
..onRecord.listen((rec) {
|
..onRecord.listen((rec) {
|
||||||
print(rec);
|
print(rec);
|
||||||
|
@ -29,7 +30,7 @@ main() async {
|
||||||
renderHtml(
|
renderHtml(
|
||||||
enforceAcceptHeader: true,
|
enforceAcceptHeader: true,
|
||||||
renderer: StringRenderer(
|
renderer: StringRenderer(
|
||||||
doctype: null,
|
//doctype: null,
|
||||||
pretty: false,
|
pretty: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -7,20 +7,21 @@ import 'package:html_builder/html_builder.dart';
|
||||||
/// You can provide a custom [renderer]. The default renders minified HTML5 pages.
|
/// You can provide a custom [renderer]. The default renders minified HTML5 pages.
|
||||||
///
|
///
|
||||||
/// Set [enforceAcceptHeader] to `true` to throw a `406 Not Acceptable` if the client doesn't accept HTML responses.
|
/// Set [enforceAcceptHeader] to `true` to throw a `406 Not Acceptable` if the client doesn't accept HTML responses.
|
||||||
RequestHandler renderHtml({StringRenderer renderer, bool enforceAcceptHeader}) {
|
RequestHandler renderHtml({StringRenderer? renderer, bool? enforceAcceptHeader}) {
|
||||||
renderer ??= new StringRenderer(pretty: false, html5: true);
|
renderer ??= StringRenderer(pretty: false, html5: true);
|
||||||
|
|
||||||
return (RequestContext req, ResponseContext res) {
|
return (RequestContext req, ResponseContext res) {
|
||||||
var oldSerializer = res.serializer;
|
var oldSerializer = res.serializer;
|
||||||
|
|
||||||
res.serializer = (data) {
|
res.serializer = (data) {
|
||||||
if (data is! Node)
|
if (data is! Node) {
|
||||||
return oldSerializer(data);
|
return oldSerializer!(data);
|
||||||
else {
|
} else {
|
||||||
if (enforceAcceptHeader == true && !req.accepts('text/html'))
|
if (enforceAcceptHeader == true && !req.accepts('text/html')) {
|
||||||
throw new AngelHttpException.notAcceptable();
|
throw AngelHttpException.notAcceptable();
|
||||||
|
}
|
||||||
|
|
||||||
var content = renderer.render(data as Node);
|
var content = renderer!.render(data);
|
||||||
res
|
res
|
||||||
..headers['content-type'] = 'text/html'
|
..headers['content-type'] = 'text/html'
|
||||||
..write(content);
|
..write(content);
|
||||||
|
@ -29,6 +30,6 @@ RequestHandler renderHtml({StringRenderer renderer, bool enforceAcceptHeader}) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Future<bool>.value(true);
|
return Future<bool>.value(true);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,28 @@
|
||||||
name: angel_html
|
name: angel_html
|
||||||
version: 2.0.0
|
version: 3.0.0
|
||||||
description: Support for rendering html_builder AST's as responses in Angel.
|
description: Support for rendering html_builder AST's as responses in Angel.
|
||||||
author: Tobe O <thosakwe@gmail.com>
|
|
||||||
homepage: https://github.com/angel-dart/html_builder
|
homepage: https://github.com/angel-dart/html_builder
|
||||||
|
publish_to: none
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.10.0 <2.12.0"
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
angel_framework: #^2.0.0-alpha
|
angel_framework:
|
||||||
path: ../framework
|
git:
|
||||||
html_builder: ^1.0.0
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
|
ref: sdk-2.12.x_nnbd
|
||||||
|
path: packages/framework
|
||||||
|
html_builder:
|
||||||
|
git:
|
||||||
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
|
ref: sdk-2.12.x_nnbd
|
||||||
|
path: packages/html_builder
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
angel_test: #^2.0.0-alpha
|
angel_test:
|
||||||
path: ../test
|
git:
|
||||||
html: ^0.13.2
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
logging: ^0.11.0
|
ref: sdk-2.12.x_nnbd
|
||||||
test: ^1.15.7
|
path: packages/test
|
||||||
pedantic: ^1.0.0
|
html: ^0.15.0
|
||||||
|
logging: ^1.0.1
|
||||||
|
test: ^1.17.0
|
||||||
|
pedantic: ^1.11.0
|
|
@ -5,12 +5,12 @@ import 'package:html_builder/elements.dart';
|
||||||
import 'package:html_builder/html_builder.dart';
|
import 'package:html_builder/html_builder.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
main() {
|
void main() {
|
||||||
Angel app;
|
Angel app;
|
||||||
TestClient client;
|
late TestClient client;
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
app = new Angel();
|
app = Angel();
|
||||||
|
|
||||||
app.fallback(renderHtml());
|
app.fallback(renderHtml());
|
||||||
|
|
||||||
|
@ -27,8 +27,8 @@ main() {
|
||||||
chain([
|
chain([
|
||||||
renderHtml(
|
renderHtml(
|
||||||
enforceAcceptHeader: true,
|
enforceAcceptHeader: true,
|
||||||
renderer: new StringRenderer(
|
renderer: StringRenderer(
|
||||||
doctype: null,
|
//doctype: null,
|
||||||
pretty: false,
|
pretty: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -43,7 +43,7 @@ main() {
|
||||||
tearDown(() => client.close());
|
tearDown(() => client.close());
|
||||||
|
|
||||||
test('sets content type and body', () async {
|
test('sets content type and body', () async {
|
||||||
var response = await client.get('/html');
|
var response = await client.get(Uri.parse('/html'));
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.body}');
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
|
@ -56,12 +56,13 @@ main() {
|
||||||
|
|
||||||
group('enforce accept header', () {
|
group('enforce accept header', () {
|
||||||
test('sends if correct accept or wildcard', () async {
|
test('sends if correct accept or wildcard', () async {
|
||||||
var response = await client.get('/strict', headers: {'accept': '*/*'});
|
var response =
|
||||||
|
await client.get(Uri.parse('/strict'), headers: {'accept': '*/*'});
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.body}');
|
||||||
expect(response,
|
expect(response,
|
||||||
allOf(hasContentType('text/html'), hasBody('<div>strict</div>')));
|
allOf(hasContentType('text/html'), hasBody('<div>strict</div>')));
|
||||||
|
|
||||||
response = await client.get('/strict',
|
response = await client.get(Uri.parse('/strict'),
|
||||||
headers: {'accept': 'text/html,application/json,text/xml'});
|
headers: {'accept': 'text/html,application/json,text/xml'});
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.body}');
|
||||||
expect(response,
|
expect(response,
|
||||||
|
@ -69,12 +70,12 @@ main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('throws if incorrect or no accept', () async {
|
test('throws if incorrect or no accept', () async {
|
||||||
var response = await client.get('/strict');
|
var response = await client.get(Uri.parse('/strict'));
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.statusCode} ${response.body}');
|
||||||
expect(response, hasStatus(406));
|
expect(response, hasStatus(406));
|
||||||
|
|
||||||
response = await client
|
response = await client.get(Uri.parse('/strict'),
|
||||||
.get('/strict', headers: {'accept': 'application/json,text/xml'});
|
headers: {'accept': 'application/json,text/xml'});
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.body}');
|
||||||
expect(response,
|
expect(response,
|
||||||
isAngelHttpException(statusCode: 406, message: '406 Not Acceptable'));
|
isAngelHttpException(statusCode: 406, message: '406 Not Acceptable'));
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
include: package:pedantic/analysis_options.yaml
|
||||||
analyzer:
|
analyzer:
|
||||||
strong-mode:
|
strong-mode:
|
||||||
implicit-casts: false
|
implicit-casts: false
|
|
@ -7,8 +7,8 @@ import 'package:io/io.dart';
|
||||||
import 'package:jael_language_server/jael_language_server.dart';
|
import 'package:jael_language_server/jael_language_server.dart';
|
||||||
import 'package:jael_language_server/src/protocol/language_server/server.dart';
|
import 'package:jael_language_server/src/protocol/language_server/server.dart';
|
||||||
|
|
||||||
main(List<String> args) async {
|
void main(List<String> args) async {
|
||||||
var argParser = new ArgParser()
|
var argParser = ArgParser()
|
||||||
..addFlag('help',
|
..addFlag('help',
|
||||||
abbr: 'h', negatable: false, help: 'Print this help information.')
|
abbr: 'h', negatable: false, help: 'Print this help information.')
|
||||||
..addOption('log-file', help: 'A path to which to write a log file.');
|
..addOption('log-file', help: 'A path to which to write a log file.');
|
||||||
|
@ -25,14 +25,14 @@ main(List<String> args) async {
|
||||||
printUsage();
|
printUsage();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
var jaelServer = new JaelLanguageServer();
|
var jaelServer = JaelLanguageServer();
|
||||||
|
|
||||||
if (argResults.wasParsed('log-file')) {
|
if (argResults.wasParsed('log-file')) {
|
||||||
var f = new File(argResults['log-file'] as String);
|
var f = File(argResults['log-file'] as String);
|
||||||
await f.create(recursive: true);
|
await f.create(recursive: true);
|
||||||
|
|
||||||
jaelServer.logger.onRecord.listen((rec) async {
|
jaelServer.logger.onRecord.listen((rec) async {
|
||||||
var sink = await f.openWrite(mode: FileMode.append);
|
var sink = f.openWrite(mode: FileMode.append);
|
||||||
sink.writeln(rec);
|
sink.writeln(rec);
|
||||||
if (rec.error != null) sink.writeln(rec.error);
|
if (rec.error != null) sink.writeln(rec.error);
|
||||||
if (rec.stackTrace != null) sink.writeln(rec.stackTrace);
|
if (rec.stackTrace != null) sink.writeln(rec.stackTrace);
|
||||||
|
@ -47,7 +47,7 @@ main(List<String> args) async {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var spec = new ZoneSpecification(
|
var spec = ZoneSpecification(
|
||||||
handleUncaughtError: (self, parent, zone, error, stackTrace) {
|
handleUncaughtError: (self, parent, zone, error, stackTrace) {
|
||||||
jaelServer.logger.severe('Uncaught', error, stackTrace);
|
jaelServer.logger.severe('Uncaught', error, stackTrace);
|
||||||
},
|
},
|
||||||
|
@ -57,7 +57,7 @@ main(List<String> args) async {
|
||||||
);
|
);
|
||||||
var zone = Zone.current.fork(specification: spec);
|
var zone = Zone.current.fork(specification: spec);
|
||||||
await zone.run(() async {
|
await zone.run(() async {
|
||||||
var stdio = new StdIOLanguageServer.start(jaelServer);
|
var stdio = StdIOLanguageServer.start(jaelServer);
|
||||||
await stdio.onDone;
|
await stdio.onDone;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,18 +7,19 @@ class Analyzer extends Parser {
|
||||||
final Logger logger;
|
final Logger logger;
|
||||||
Analyzer(Scanner scanner, this.logger) : super(scanner);
|
Analyzer(Scanner scanner, this.logger) : super(scanner);
|
||||||
|
|
||||||
|
@override
|
||||||
final errors = <JaelError>[];
|
final errors = <JaelError>[];
|
||||||
var _scope = new SymbolTable<JaelObject>();
|
SymbolTable<JaelObject>? _scope = SymbolTable<JaelObject>();
|
||||||
var allDefinitions = <Variable<JaelObject>>[];
|
var allDefinitions = <Variable<JaelObject>>[];
|
||||||
|
|
||||||
SymbolTable<JaelObject> get parentScope =>
|
SymbolTable<JaelObject>? get parentScope =>
|
||||||
_scope.isRoot ? _scope : _scope.parent;
|
_scope!.isRoot ? _scope : _scope!.parent;
|
||||||
|
|
||||||
SymbolTable<JaelObject> get scope => _scope;
|
SymbolTable<JaelObject>? get scope => _scope;
|
||||||
|
|
||||||
bool ensureAttributeIsPresent(Element element, String name) {
|
bool ensureAttributeIsPresent(Element element, String name) {
|
||||||
if (element.getAttribute(name)?.value == null) {
|
if (element.getAttribute(name)?.value == null) {
|
||||||
addError(new JaelError(JaelErrorSeverity.error,
|
addError(JaelError(JaelErrorSeverity.error,
|
||||||
'Missing required attribute `$name`.', element.span));
|
'Missing required attribute `$name`.', element.span));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -33,9 +34,9 @@ class Analyzer extends Parser {
|
||||||
bool ensureAttributeIsConstantString(Element element, String name) {
|
bool ensureAttributeIsConstantString(Element element, String name) {
|
||||||
var a = element.getAttribute(name);
|
var a = element.getAttribute(name);
|
||||||
if (a?.value is! StringLiteral || a?.value == null) {
|
if (a?.value is! StringLiteral || a?.value == null) {
|
||||||
var e = new JaelError(
|
var e = JaelError(
|
||||||
JaelErrorSeverity.warning,
|
JaelErrorSeverity.warning,
|
||||||
"`$name` attribute should be a constant string literal.",
|
'`$name` attribute should be a constant string literal.',
|
||||||
a?.span ?? element.tagName.span);
|
a?.span ?? element.tagName.span);
|
||||||
addError(e);
|
addError(e);
|
||||||
return false;
|
return false;
|
||||||
|
@ -45,18 +46,18 @@ class Analyzer extends Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Element parseElement() {
|
Element? parseElement() {
|
||||||
try {
|
try {
|
||||||
_scope = _scope.createChild();
|
_scope = _scope!.createChild();
|
||||||
var element = super.parseElement();
|
var element = super.parseElement();
|
||||||
if (element == null) return null;
|
if (element == null) return null;
|
||||||
|
|
||||||
// Check if any custom element exists.
|
// Check if any custom element exists.
|
||||||
_scope
|
_scope!
|
||||||
.resolve(element.tagName.name)
|
.resolve(element.tagName.name)
|
||||||
?.value
|
?.value
|
||||||
?.usages
|
?.usages
|
||||||
?.add(new SymbolUsage(SymbolUsageType.read, element.span));
|
.add(SymbolUsage(SymbolUsageType.read, element.span));
|
||||||
|
|
||||||
// Validate attrs
|
// Validate attrs
|
||||||
var forEach = element.getAttribute('for-each');
|
var forEach = element.getAttribute('for-each');
|
||||||
|
@ -64,14 +65,14 @@ class Analyzer extends Parser {
|
||||||
var asAttr = element.getAttribute('as');
|
var asAttr = element.getAttribute('as');
|
||||||
if (asAttr != null) {
|
if (asAttr != null) {
|
||||||
if (ensureAttributeIsConstantString(element, 'as')) {
|
if (ensureAttributeIsConstantString(element, 'as')) {
|
||||||
var asName = asAttr.string.value;
|
var asName = asAttr.string!.value;
|
||||||
_scope.create(asName,
|
_scope!.create(asName,
|
||||||
value: new JaelVariable(asName, asAttr.span), constant: true);
|
value: JaelVariable(asName, asAttr.span), constant: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (forEach.value != null) {
|
if (forEach.value != null) {
|
||||||
addError(new JaelError(JaelErrorSeverity.error,
|
addError(JaelError(JaelErrorSeverity.error,
|
||||||
'Missing value for `for-each` directive.', forEach.span));
|
'Missing value for `for-each` directive.', forEach.span));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +80,7 @@ class Analyzer extends Parser {
|
||||||
var iff = element.getAttribute('if');
|
var iff = element.getAttribute('if');
|
||||||
if (iff != null) {
|
if (iff != null) {
|
||||||
if (iff.value != null) {
|
if (iff.value != null) {
|
||||||
addError(new JaelError(JaelErrorSeverity.error,
|
addError(JaelError(JaelErrorSeverity.error,
|
||||||
'Missing value for `iff` directive.', iff.span));
|
'Missing value for `iff` directive.', iff.span));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,29 +95,29 @@ class Analyzer extends Parser {
|
||||||
//logger.info('Found <case> at ${element.span.start.toolString}');
|
//logger.info('Found <case> at ${element.span.start.toolString}');
|
||||||
} else if (element.tagName.name == 'declare') {
|
} else if (element.tagName.name == 'declare') {
|
||||||
if (element.attributes.isEmpty) {
|
if (element.attributes.isEmpty) {
|
||||||
addError(new JaelError(
|
addError(JaelError(
|
||||||
JaelErrorSeverity.warning,
|
JaelErrorSeverity.warning,
|
||||||
'`declare` directive does not define any new symbols.',
|
'`declare` directive does not define any new symbols.',
|
||||||
element.tagName.span));
|
element.tagName.span));
|
||||||
} else {
|
} else {
|
||||||
for (var attr in element.attributes) {
|
for (var attr in element.attributes) {
|
||||||
_scope.create(attr.name,
|
_scope!
|
||||||
value: new JaelVariable(attr.name, attr.span));
|
.create(attr.name, value: JaelVariable(attr.name, attr.span));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (element.tagName.name == 'element') {
|
} else if (element.tagName.name == 'element') {
|
||||||
if (ensureAttributeIsConstantString(element, 'name')) {
|
if (ensureAttributeIsConstantString(element, 'name')) {
|
||||||
var nameCtx = element.getAttribute('name').value as StringLiteral;
|
var nameCtx = element.getAttribute('name')!.value as StringLiteral;
|
||||||
var name = nameCtx.value;
|
var name = nameCtx.value;
|
||||||
//logger.info(
|
//logger.info(
|
||||||
// 'Found custom element $name at ${element.span.start.toolString}');
|
// 'Found custom element $name at ${element.span.start.toolString}');
|
||||||
try {
|
try {
|
||||||
var symbol = parentScope.create(name,
|
var symbol = parentScope!.create(name,
|
||||||
value: new JaelCustomElement(name, element.tagName.span),
|
value: JaelCustomElement(name, element.tagName.span),
|
||||||
constant: true);
|
constant: true);
|
||||||
allDefinitions.add(symbol);
|
allDefinitions.add(symbol);
|
||||||
} on StateError catch (e) {
|
} on StateError catch (e) {
|
||||||
addError(new JaelError(
|
addError(JaelError(
|
||||||
JaelErrorSeverity.error, e.message, element.tagName.span));
|
JaelErrorSeverity.error, e.message, element.tagName.span));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,19 +134,19 @@ class Analyzer extends Parser {
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
} finally {
|
} finally {
|
||||||
_scope = _scope.parent;
|
_scope = _scope!.parent;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Expression parseExpression(int precedence) {
|
Expression? parseExpression(int precedence) {
|
||||||
var expr = super.parseExpression(precedence);
|
var expr = super.parseExpression(precedence);
|
||||||
if (expr == null) return null;
|
if (expr == null) return null;
|
||||||
|
|
||||||
if (expr is Identifier) {
|
if (expr is Identifier) {
|
||||||
var ref = _scope.resolve(expr.name);
|
var ref = _scope!.resolve(expr.name);
|
||||||
ref?.value?.usages?.add(new SymbolUsage(SymbolUsageType.read, expr.span));
|
ref?.value?.usages.add(SymbolUsage(SymbolUsageType.read, expr.span));
|
||||||
}
|
}
|
||||||
|
|
||||||
return expr;
|
return expr;
|
||||||
|
|
|
@ -11,13 +11,15 @@ abstract class JaelObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
class JaelCustomElement extends JaelObject {
|
class JaelCustomElement extends JaelObject {
|
||||||
|
@override
|
||||||
final String name;
|
final String name;
|
||||||
final attributes = new SplayTreeSet<String>();
|
final attributes = SplayTreeSet<String>();
|
||||||
|
|
||||||
JaelCustomElement(this.name, FileSpan span) : super(span);
|
JaelCustomElement(this.name, FileSpan span) : super(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
class JaelVariable extends JaelObject {
|
class JaelVariable extends JaelObject {
|
||||||
|
@override
|
||||||
final String name;
|
final String name;
|
||||||
JaelVariable(this.name, FileSpan span) : super(span);
|
JaelVariable(this.name, FileSpan span) : super(span);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,8 @@ abstract class LanguageServer {
|
||||||
_onDone.complete();
|
_onDone.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ServerCapabilities> initialize(int clientPid, String rootUri,
|
Future<ServerCapabilities> initialize(int? clientPid, String? rootUri,
|
||||||
ClientCapabilities clientCapabilities, String trace) async =>
|
ClientCapabilities clientCapabilities, String? trace) async =>
|
||||||
ServerCapabilities((b) => b);
|
ServerCapabilities((b) => b);
|
||||||
void initialized() {}
|
void initialized() {}
|
||||||
void textDocumentDidOpen(TextDocumentItem document) {}
|
void textDocumentDidOpen(TextDocumentItem document) {}
|
||||||
|
@ -24,7 +24,7 @@ abstract class LanguageServer {
|
||||||
Future<CompletionList> textDocumentCompletion(
|
Future<CompletionList> textDocumentCompletion(
|
||||||
TextDocumentIdentifier documentId, Position position) async =>
|
TextDocumentIdentifier documentId, Position position) async =>
|
||||||
CompletionList((b) => b);
|
CompletionList((b) => b);
|
||||||
Future<Location> textDocumentDefinition(
|
Future<Location?> textDocumentDefinition(
|
||||||
TextDocumentIdentifier documentId, Position position) async =>
|
TextDocumentIdentifier documentId, Position position) async =>
|
||||||
null;
|
null;
|
||||||
Future<List<Location>> textDocumentReferences(
|
Future<List<Location>> textDocumentReferences(
|
||||||
|
@ -41,7 +41,7 @@ abstract class LanguageServer {
|
||||||
Future<List<SymbolInformation>> textDocumentSymbols(
|
Future<List<SymbolInformation>> textDocumentSymbols(
|
||||||
TextDocumentIdentifier documentId) async =>
|
TextDocumentIdentifier documentId) async =>
|
||||||
[];
|
[];
|
||||||
Future<List<SymbolInformation>> workspaceSymbol(String query) async => [];
|
Future<List<SymbolInformation>> workspaceSymbol(String? query) async => [];
|
||||||
Future<dynamic> textDocumentHover(
|
Future<dynamic> textDocumentHover(
|
||||||
TextDocumentIdentifier documentId, Position position) async =>
|
TextDocumentIdentifier documentId, Position position) async =>
|
||||||
null;
|
null;
|
||||||
|
@ -51,13 +51,13 @@ abstract class LanguageServer {
|
||||||
CodeActionContext context) async =>
|
CodeActionContext context) async =>
|
||||||
[];
|
[];
|
||||||
Future<void> workspaceExecuteCommand(
|
Future<void> workspaceExecuteCommand(
|
||||||
String command, List<dynamic> arguments) async {}
|
String? command, List<dynamic>? arguments) async {}
|
||||||
Future<WorkspaceEdit> textDocumentRename(TextDocumentIdentifier documentId,
|
Future<WorkspaceEdit?> textDocumentRename(TextDocumentIdentifier documentId,
|
||||||
Position position, String newName) async =>
|
Position position, String? newName) async =>
|
||||||
null;
|
null;
|
||||||
Stream<Diagnostics> get diagnostics => Stream.empty();
|
Stream<Diagnostics> get diagnostics => Stream.empty();
|
||||||
Stream<ApplyWorkspaceEditParams> get workspaceEdits => Stream.empty();
|
Stream<ApplyWorkspaceEditParams> get workspaceEdits => Stream.empty();
|
||||||
Stream<ShowMessageParams> get showMessages => Stream.empty();
|
Stream<ShowMessageParams>? get showMessages => Stream.empty();
|
||||||
Stream<ShowMessageParams> get logMessages => Stream.empty();
|
Stream<ShowMessageParams> get logMessages => Stream.empty();
|
||||||
|
|
||||||
void setupExtraMethods(Peer peer) {}
|
void setupExtraMethods(Peer peer) {}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -10,7 +10,7 @@ import 'wireformat.dart';
|
||||||
/// A Language Server communicating over stdin and stdout.
|
/// A Language Server communicating over stdin and stdout.
|
||||||
class StdIOLanguageServer {
|
class StdIOLanguageServer {
|
||||||
final LanguageServer _server;
|
final LanguageServer _server;
|
||||||
Future<void> onDone;
|
Future<void>? onDone;
|
||||||
|
|
||||||
/// Wrap [_server] and register RPC methods using the LSP wire protocol.
|
/// Wrap [_server] and register RPC methods using the LSP wire protocol.
|
||||||
///
|
///
|
||||||
|
@ -38,10 +38,10 @@ class StdIOLanguageServer {
|
||||||
peer
|
peer
|
||||||
..registerMethod('initialize', (params) async {
|
..registerMethod('initialize', (params) async {
|
||||||
final serverCapabilities = await _server.initialize(
|
final serverCapabilities = await _server.initialize(
|
||||||
params['processId'].valueOr(0) as int,
|
params['processId'].valueOr(0) as int?,
|
||||||
params['rootUri'].valueOr('') as String,
|
params['rootUri'].valueOr('') as String?,
|
||||||
ClientCapabilities.fromJson(params['capabilities'].value as Map),
|
ClientCapabilities.fromJson(params['capabilities'].value as Map),
|
||||||
params['trace'].valueOr('off') as String);
|
params['trace'].valueOr('off') as String?);
|
||||||
_isInitialized = true;
|
_isInitialized = true;
|
||||||
return {'capabilities': serverCapabilities.toJson()};
|
return {'capabilities': serverCapabilities.toJson()};
|
||||||
})
|
})
|
||||||
|
@ -90,7 +90,7 @@ class StdIOLanguageServer {
|
||||||
})
|
})
|
||||||
..logMessages.map((e) => e.toJson()).forEach(
|
..logMessages.map((e) => e.toJson()).forEach(
|
||||||
(message) => peer.sendNotification('window/logMessage', message))
|
(message) => peer.sendNotification('window/logMessage', message))
|
||||||
..showMessages.map((e) => e.toJson()).forEach(
|
..showMessages!.map((e) => e.toJson()).forEach(
|
||||||
(message) => peer.sendNotification('window/showMessage', message));
|
(message) => peer.sendNotification('window/showMessage', message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,31 +122,31 @@ class StdIOLanguageServer {
|
||||||
(params) => _server
|
(params) => _server
|
||||||
.textDocumentReferences(
|
.textDocumentReferences(
|
||||||
_document(params), _position(params), _referenceContext(params))
|
_document(params), _position(params), _referenceContext(params))
|
||||||
.then((r) => r?.map((e) => e.toJson())?.toList()));
|
.then((r) => r.map((e) => e.toJson()).toList()));
|
||||||
_registerRequest(
|
_registerRequest(
|
||||||
peer,
|
peer,
|
||||||
'textDocument/implementation',
|
'textDocument/implementation',
|
||||||
(params) => _server
|
(params) => _server
|
||||||
.textDocumentImplementation(_document(params), _position(params))
|
.textDocumentImplementation(_document(params), _position(params))
|
||||||
.then((r) => r?.map((e) => e.toJson())?.toList()));
|
.then((r) => r.map((e) => e.toJson()).toList()));
|
||||||
_registerRequest(
|
_registerRequest(
|
||||||
peer,
|
peer,
|
||||||
'textDocument/documentHighlight',
|
'textDocument/documentHighlight',
|
||||||
(params) => _server
|
(params) => _server
|
||||||
.textDocumentHighlight(_document(params), _position(params))
|
.textDocumentHighlight(_document(params), _position(params))
|
||||||
.then((r) => r?.map((e) => e.toJson())?.toList()));
|
.then((r) => r.map((e) => e.toJson()).toList()));
|
||||||
_registerRequest(
|
_registerRequest(
|
||||||
peer,
|
peer,
|
||||||
'textDocument/documentSymbol',
|
'textDocument/documentSymbol',
|
||||||
(params) => _server
|
(params) => _server
|
||||||
.textDocumentSymbols(_document(params))
|
.textDocumentSymbols(_document(params))
|
||||||
.then((r) => r?.map((e) => e.toJson())?.toList()));
|
.then((r) => r.map((e) => e.toJson()).toList()));
|
||||||
_registerRequest(
|
_registerRequest(
|
||||||
peer,
|
peer,
|
||||||
'workspace/symbol',
|
'workspace/symbol',
|
||||||
(params) => _server
|
(params) => _server
|
||||||
.workspaceSymbol(_query(params))
|
.workspaceSymbol(_query(params))
|
||||||
.then((r) => r?.map((e) => e.toJson())?.toList()));
|
.then((r) => r.map((e) => e.toJson()).toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _codeActionMethods(Peer peer) {
|
void _codeActionMethods(Peer peer) {
|
||||||
|
@ -156,18 +156,18 @@ class StdIOLanguageServer {
|
||||||
(params) => _server
|
(params) => _server
|
||||||
.textDocumentCodeAction(
|
.textDocumentCodeAction(
|
||||||
_document(params), _range(params), _codeActionContext(params))
|
_document(params), _range(params), _codeActionContext(params))
|
||||||
.then((r) => r?.map((e) => e.toJson())?.toList()));
|
.then((r) => r.map((e) => e.toJson()).toList()));
|
||||||
_registerRequest(
|
_registerRequest(
|
||||||
peer,
|
peer,
|
||||||
'workspace/executeCommand',
|
'workspace/executeCommand',
|
||||||
(params) => _server.workspaceExecuteCommand(
|
(params) => _server.workspaceExecuteCommand(
|
||||||
params['command'].value as String,
|
params['command'].value as String?,
|
||||||
params['arguments']?.value as List));
|
params['arguments']?.value as List?));
|
||||||
_registerRequest(
|
_registerRequest(
|
||||||
peer,
|
peer,
|
||||||
'textDocument/rename',
|
'textDocument/rename',
|
||||||
(params) async => (await _server.textDocumentRename(_document(params),
|
(params) async => (await _server.textDocumentRename(_document(params),
|
||||||
_position(params), params['newName'].value as String))
|
_position(params), params['newName'].value as String?))!
|
||||||
.toJson());
|
.toJson());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,4 +198,4 @@ List<TextDocumentContentChangeEvent> _contentChanges(params) =>
|
||||||
.map((change) => TextDocumentContentChangeEvent.fromJson(change as Map))
|
.map((change) => TextDocumentContentChangeEvent.fromJson(change as Map))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
String _query(params) => params['query'].value as String;
|
String? _query(params) => params['query'].value as String?;
|
||||||
|
|
|
@ -33,7 +33,7 @@ class _Parser {
|
||||||
bool _headerMode = true;
|
bool _headerMode = true;
|
||||||
int _contentLength = -1;
|
int _contentLength = -1;
|
||||||
|
|
||||||
StreamSubscription _subscription;
|
late StreamSubscription _subscription;
|
||||||
|
|
||||||
_Parser(Stream<List<int>> stream) {
|
_Parser(Stream<List<int>> stream) {
|
||||||
_subscription =
|
_subscription =
|
||||||
|
|
|
@ -17,14 +17,14 @@ import 'protocol/language_server/interface.dart';
|
||||||
import 'protocol/language_server/messages.dart';
|
import 'protocol/language_server/messages.dart';
|
||||||
|
|
||||||
class JaelLanguageServer extends LanguageServer {
|
class JaelLanguageServer extends LanguageServer {
|
||||||
var _diagnostics = new StreamController<Diagnostics>();
|
final _diagnostics = StreamController<Diagnostics>();
|
||||||
var _done = new Completer();
|
final _done = Completer();
|
||||||
var _memFs = new MemoryFileSystem();
|
final _memFs = MemoryFileSystem();
|
||||||
var _localFs = const LocalFileSystem();
|
final _localFs = const LocalFileSystem();
|
||||||
Directory _localRootDir, _memRootDir;
|
Directory? _localRootDir, _memRootDir;
|
||||||
var logger = new Logger('jael');
|
var logger = Logger('jael');
|
||||||
Uri _rootUri;
|
late Uri _rootUri;
|
||||||
var _workspaceEdits = new StreamController<ApplyWorkspaceEditParams>();
|
final _workspaceEdits = StreamController<ApplyWorkspaceEditParams>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<Diagnostics> get diagnostics => _diagnostics.stream;
|
Stream<Diagnostics> get diagnostics => _diagnostics.stream;
|
||||||
|
@ -48,24 +48,24 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
peer.registerMethod('textDocument/formatting',
|
peer.registerMethod('textDocument/formatting',
|
||||||
(json_rpc_2.Parameters params) async {
|
(json_rpc_2.Parameters params) async {
|
||||||
var documentId =
|
var documentId =
|
||||||
new TextDocumentIdentifier.fromJson(params['textDocument'].asMap);
|
TextDocumentIdentifier.fromJson(params['textDocument'].asMap);
|
||||||
var formattingOptions =
|
var formattingOptions =
|
||||||
new FormattingOptions.fromJson(params['options'].asMap);
|
FormattingOptions.fromJson(params['options'].asMap);
|
||||||
return await textDocumentFormatting(documentId, formattingOptions);
|
return await textDocumentFormatting(documentId, formattingOptions);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<ServerCapabilities> initialize(int clientPid, String rootUri,
|
Future<ServerCapabilities> initialize(int? clientPid, String? rootUri,
|
||||||
ClientCapabilities clientCapabilities, String trace) async {
|
ClientCapabilities clientCapabilities, String? trace) async {
|
||||||
// Find our real root dir.
|
// Find our real root dir.
|
||||||
_localRootDir = _localFs.directory(_rootUri = Uri.parse(rootUri));
|
_localRootDir = _localFs.directory(_rootUri = Uri.parse(rootUri!));
|
||||||
_memRootDir = _memFs.directory('/');
|
_memRootDir = _memFs.directory('/');
|
||||||
await _memRootDir.create(recursive: true);
|
await _memRootDir!.create(recursive: true);
|
||||||
_memFs.currentDirectory = _memRootDir;
|
_memFs.currentDirectory = _memRootDir;
|
||||||
|
|
||||||
// Copy all real files that end in *.jael (and *.jl for legacy) into the in-memory filesystem.
|
// Copy all real files that end in *.jael (and *.jl for legacy) into the in-memory filesystem.
|
||||||
await for (var entity in _localRootDir.list(recursive: true)) {
|
await for (var entity in _localRootDir!.list(recursive: true)) {
|
||||||
if (entity is File && p.extension(entity.path) == '.jael') {
|
if (entity is File && p.extension(entity.path) == '.jael') {
|
||||||
logger.info('HEY ${entity.path}');
|
logger.info('HEY ${entity.path}');
|
||||||
var file = _memFs.file(entity.absolute.path);
|
var file = _memFs.file(entity.absolute.path);
|
||||||
|
@ -78,24 +78,24 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
'Found Jael file ${file.path}; copied to ${file.absolute.path}');
|
'Found Jael file ${file.path}; copied to ${file.absolute.path}');
|
||||||
|
|
||||||
// Analyze it
|
// Analyze it
|
||||||
var documentId = new TextDocumentIdentifier((b) {
|
var documentId = TextDocumentIdentifier((b) {
|
||||||
b..uri = _rootUri.replace(path: file.path).toString();
|
b.uri = _rootUri.replace(path: file.path).toString();
|
||||||
});
|
});
|
||||||
|
|
||||||
await analyzerForId(documentId);
|
await analyzerForId(documentId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ServerCapabilities((b) {
|
return ServerCapabilities((b) {
|
||||||
b
|
b
|
||||||
..codeActionProvider = false
|
..codeActionProvider = false
|
||||||
..completionProvider = new CompletionOptions((b) {
|
..completionProvider = CompletionOptions((b) {
|
||||||
b
|
b
|
||||||
..resolveProvider = true
|
..resolveProvider = true
|
||||||
..triggerCharacters =
|
..triggerCharacters =
|
||||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdeghijklmnopqrstuvxwyz'
|
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdeghijklmnopqrstuvxwyz'
|
||||||
.codeUnits
|
.codeUnits
|
||||||
.map((c) => new String.fromCharCode(c))
|
.map((c) => String.fromCharCode(c))
|
||||||
.toList();
|
.toList();
|
||||||
})
|
})
|
||||||
..definitionProvider = true
|
..definitionProvider = true
|
||||||
|
@ -108,13 +108,13 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
..implementationProvider = true
|
..implementationProvider = true
|
||||||
..referencesProvider = true
|
..referencesProvider = true
|
||||||
..renameProvider = true
|
..renameProvider = true
|
||||||
..signatureHelpProvider = new SignatureHelpOptions((b) {})
|
..signatureHelpProvider = SignatureHelpOptions((b) {})
|
||||||
..textDocumentSync = new TextDocumentSyncOptions((b) {
|
..textDocumentSync = TextDocumentSyncOptions((b) {
|
||||||
b
|
b
|
||||||
..openClose = true
|
..openClose = true
|
||||||
..change = TextDocumentSyncKind.full
|
..change = TextDocumentSyncKind.full
|
||||||
..save = new SaveOptions((b) {
|
..save = SaveOptions((b) {
|
||||||
b..includeText = false;
|
b.includeText = false;
|
||||||
})
|
})
|
||||||
..willSave = false
|
..willSave = false
|
||||||
..willSaveWaitUntil = false;
|
..willSaveWaitUntil = false;
|
||||||
|
@ -124,7 +124,7 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<File> fileForId(TextDocumentIdentifier documentId) async {
|
Future<File> fileForId(TextDocumentIdentifier documentId) async {
|
||||||
var uri = Uri.parse(documentId.uri);
|
var uri = Uri.parse(documentId.uri!);
|
||||||
var relativePath = uri.path;
|
var relativePath = uri.path;
|
||||||
var file = _memFs.directory('/').childFile(relativePath);
|
var file = _memFs.directory('/').childFile(relativePath);
|
||||||
|
|
||||||
|
@ -156,14 +156,14 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
|
|
||||||
Future<Analyzer> analyzerForId(TextDocumentIdentifier documentId) async {
|
Future<Analyzer> analyzerForId(TextDocumentIdentifier documentId) async {
|
||||||
var scanner = await scannerForId(documentId);
|
var scanner = await scannerForId(documentId);
|
||||||
var analyzer = new Analyzer(scanner, logger)..errors.addAll(scanner.errors);
|
var analyzer = Analyzer(scanner, logger)..errors.addAll(scanner.errors);
|
||||||
analyzer.parseDocument();
|
analyzer.parseDocument();
|
||||||
emitDiagnostics(documentId.uri, analyzer.errors.map(toDiagnostic).toList());
|
emitDiagnostics(documentId.uri, analyzer.errors.map(toDiagnostic).toList());
|
||||||
return analyzer;
|
return analyzer;
|
||||||
}
|
}
|
||||||
|
|
||||||
Diagnostic toDiagnostic(JaelError e) {
|
Diagnostic toDiagnostic(JaelError e) {
|
||||||
return new Diagnostic((b) {
|
return Diagnostic((b) {
|
||||||
b
|
b
|
||||||
..message = e.message
|
..message = e.message
|
||||||
..range = toRange(e.span)
|
..range = toRange(e.span)
|
||||||
|
@ -182,7 +182,7 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
Range toRange(FileSpan span) {
|
Range toRange(FileSpan span) {
|
||||||
return new Range((b) {
|
return Range((b) {
|
||||||
b
|
b
|
||||||
..start = toPosition(span.start)
|
..start = toPosition(span.start)
|
||||||
..end = toPosition(span.end);
|
..end = toPosition(span.end);
|
||||||
|
@ -190,8 +190,8 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
Range emptyRange() {
|
Range emptyRange() {
|
||||||
return new Range((b) => b
|
return Range((b) => b
|
||||||
..start = b.end = new Position((b) {
|
..start = b.end = Position((b) {
|
||||||
b
|
b
|
||||||
..character = 1
|
..character = 1
|
||||||
..line = 0;
|
..line = 0;
|
||||||
|
@ -199,15 +199,15 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
Position toPosition(SourceLocation location) {
|
Position toPosition(SourceLocation location) {
|
||||||
return new Position((b) {
|
return Position((b) {
|
||||||
b
|
b
|
||||||
..line = location.line
|
..line = location.line
|
||||||
..character = location.column;
|
..character = location.column;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Location toLocation(String uri, FileSpan span) {
|
Location toLocation(String? uri, FileSpan span) {
|
||||||
return new Location((b) {
|
return Location((b) {
|
||||||
b
|
b
|
||||||
..range = toRange(span)
|
..range = toRange(span)
|
||||||
..uri = uri;
|
..uri = uri;
|
||||||
|
@ -215,27 +215,27 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isReachable(JaelObject obj, Position position) {
|
bool isReachable(JaelObject obj, Position position) {
|
||||||
return obj.span.start.line <= position.line &&
|
return obj.span.start.line <= position.line! &&
|
||||||
obj.span.start.column <= position.character;
|
obj.span.start.column <= position.character!;
|
||||||
}
|
}
|
||||||
|
|
||||||
CompletionItem toCompletion(Variable<JaelObject> symbol) {
|
CompletionItem? toCompletion(Variable<JaelObject> symbol) {
|
||||||
var value = symbol.value;
|
var value = symbol.value;
|
||||||
|
|
||||||
if (value is JaelCustomElement) {
|
if (value is JaelCustomElement) {
|
||||||
var name = value.name;
|
var name = value.name;
|
||||||
return new CompletionItem((b) {
|
return CompletionItem((b) {
|
||||||
b
|
b
|
||||||
..kind = CompletionItemKind.classKind
|
..kind = CompletionItemKind.classKind
|
||||||
..label = symbol.name
|
..label = symbol.name
|
||||||
..textEdit = new TextEdit((b) {
|
..textEdit = TextEdit((b) {
|
||||||
b
|
b
|
||||||
..range = emptyRange()
|
..range = emptyRange()
|
||||||
..newText = '<$name\$1>\n \$2\n</name>';
|
..newText = '<$name\$1>\n \$2\n</name>';
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else if (value is JaelVariable) {
|
} else if (value is JaelVariable) {
|
||||||
return new CompletionItem((b) {
|
return CompletionItem((b) {
|
||||||
b
|
b
|
||||||
..kind = CompletionItemKind.variable
|
..kind = CompletionItemKind.variable
|
||||||
..label = symbol.name;
|
..label = symbol.name;
|
||||||
|
@ -245,8 +245,8 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitDiagnostics(String uri, Iterable<Diagnostic> diagnostics) {
|
void emitDiagnostics(String? uri, Iterable<Diagnostic> diagnostics) {
|
||||||
_diagnostics.add(new Diagnostics((b) {
|
_diagnostics.add(Diagnostics((b) {
|
||||||
logger.info('$uri => ${diagnostics.map((d) => d.message).toList()}');
|
logger.info('$uri => ${diagnostics.map((d) => d.message).toList()}');
|
||||||
b
|
b
|
||||||
..diagnostics = diagnostics.toList()
|
..diagnostics = diagnostics.toList()
|
||||||
|
@ -256,43 +256,42 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future textDocumentDidOpen(TextDocumentItem document) async {
|
Future textDocumentDidOpen(TextDocumentItem document) async {
|
||||||
await analyzerForId(
|
await analyzerForId(TextDocumentIdentifier((b) => b..uri = document.uri));
|
||||||
new TextDocumentIdentifier((b) => b..uri = document.uri));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future textDocumentDidChange(VersionedTextDocumentIdentifier documentId,
|
Future textDocumentDidChange(VersionedTextDocumentIdentifier documentId,
|
||||||
List<TextDocumentContentChangeEvent> changes) async {
|
List<TextDocumentContentChangeEvent> changes) async {
|
||||||
var id = new TextDocumentIdentifier((b) => b..uri = documentId.uri);
|
var id = TextDocumentIdentifier((b) => b..uri = documentId.uri);
|
||||||
var file = await fileForId(id);
|
var file = await fileForId(id);
|
||||||
|
|
||||||
for (var change in changes) {
|
for (var change in changes) {
|
||||||
if (change.text != null) {
|
if (change.text != null) {
|
||||||
await file.writeAsString(change.text);
|
await file.writeAsString(change.text!);
|
||||||
} else if (change.range != null) {
|
} else if (change.range != null) {
|
||||||
var contents = await file.readAsString();
|
String? contents = await file.readAsString();
|
||||||
|
|
||||||
int findIndex(Position position) {
|
int findIndex(Position position) {
|
||||||
var lines = contents.split('\n');
|
var lines = contents!.split('\n');
|
||||||
|
|
||||||
// Sum the length of the previous lines.
|
// Sum the length of the previous lines.
|
||||||
int lineLength = lines
|
var lineLength = lines
|
||||||
.take(position.line - 1)
|
.take(position.line! - 1)
|
||||||
.map((s) => s.length)
|
.map((s) => s.length)
|
||||||
.reduce((a, b) => a + b);
|
.reduce((a, b) => a + b);
|
||||||
return lineLength + position.character - 1;
|
return lineLength + position.character! - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (change.range == null) {
|
if (change.range == null) {
|
||||||
contents = change.text;
|
contents = change.text;
|
||||||
} else {
|
} else {
|
||||||
var start = findIndex(change.range.start),
|
var start = findIndex(change.range!.start!),
|
||||||
end = findIndex(change.range.end);
|
end = findIndex(change.range!.end!);
|
||||||
contents = contents.replaceRange(start, end, change.text);
|
contents = contents.replaceRange(start, end, change.text!);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info('${file.path} => $contents');
|
logger.info('${file.path} => $contents');
|
||||||
await file.writeAsString(contents);
|
await file.writeAsString(contents!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,9 +309,9 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
Future<CompletionList> textDocumentCompletion(
|
Future<CompletionList> textDocumentCompletion(
|
||||||
TextDocumentIdentifier documentId, Position position) async {
|
TextDocumentIdentifier documentId, Position position) async {
|
||||||
var analyzer = await analyzerForId(documentId);
|
var analyzer = await analyzerForId(documentId);
|
||||||
var symbols = analyzer.scope.allVariables;
|
var symbols = analyzer.scope!.allVariables;
|
||||||
var reachable = symbols.where((s) => isReachable(s.value, position));
|
var reachable = symbols.where((s) => isReachable(s.value!, position));
|
||||||
return new CompletionList((b) {
|
return CompletionList((b) {
|
||||||
b
|
b
|
||||||
..isIncomplete = false
|
..isIncomplete = false
|
||||||
..items = reachable.map(toCompletion).toList();
|
..items = reachable.map(toCompletion).toList();
|
||||||
|
@ -320,16 +319,16 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
final RegExp _id =
|
final RegExp _id =
|
||||||
new RegExp(r'(([A-Za-z][A-Za-z0-9_]*-)*([A-Za-z][A-Za-z0-9_]*))');
|
RegExp(r'(([A-Za-z][A-Za-z0-9_]*-)*([A-Za-z][A-Za-z0-9_]*))');
|
||||||
|
|
||||||
Future<String> currentName(
|
Future<String?> currentName(
|
||||||
TextDocumentIdentifier documentId, Position position) async {
|
TextDocumentIdentifier documentId, Position position) async {
|
||||||
// First, read the file.
|
// First, read the file.
|
||||||
var file = await fileForId(documentId);
|
var file = await fileForId(documentId);
|
||||||
var contents = await file.readAsString();
|
var contents = await file.readAsString();
|
||||||
|
|
||||||
// Next, find the current index.
|
// Next, find the current index.
|
||||||
var scanner = new SpanScanner(contents);
|
var scanner = SpanScanner(contents);
|
||||||
|
|
||||||
while (!scanner.isDone &&
|
while (!scanner.isDone &&
|
||||||
(scanner.state.line != position.line ||
|
(scanner.state.line != position.line ||
|
||||||
|
@ -339,10 +338,10 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
|
|
||||||
// Next, just read the name.
|
// Next, just read the name.
|
||||||
if (scanner.matches(_id)) {
|
if (scanner.matches(_id)) {
|
||||||
var longest = scanner.lastSpan.text;
|
var longest = scanner.lastSpan!.text;
|
||||||
|
|
||||||
while (scanner.matches(_id) && scanner.position > 0 && !scanner.isDone) {
|
while (scanner.matches(_id) && scanner.position > 0 && !scanner.isDone) {
|
||||||
longest = scanner.lastSpan.text;
|
longest = scanner.lastSpan!.text;
|
||||||
scanner.position--;
|
scanner.position--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,19 +351,19 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<JaelObject> currentSymbol(
|
Future<JaelObject?> currentSymbol(
|
||||||
TextDocumentIdentifier documentId, Position position) async {
|
TextDocumentIdentifier documentId, Position position) async {
|
||||||
var name = await currentName(documentId, position);
|
var name = await currentName(documentId, position);
|
||||||
if (name == null) return null;
|
if (name == null) return null;
|
||||||
var analyzer = await analyzerForId(documentId);
|
var analyzer = await analyzerForId(documentId);
|
||||||
var symbols = analyzer.allDefinitions ?? analyzer.scope.allVariables;
|
var symbols = analyzer.allDefinitions; // ?? analyzer.scope!.allVariables;
|
||||||
logger
|
logger
|
||||||
.info('Current symbols, seeking $name: ${symbols.map((v) => v.name)}');
|
.info('Current symbols, seeking $name: ${symbols.map((v) => v.name)}');
|
||||||
return analyzer.scope.resolve(name)?.value;
|
return analyzer.scope!.resolve(name)?.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Location> textDocumentDefinition(
|
Future<Location?> textDocumentDefinition(
|
||||||
TextDocumentIdentifier documentId, Position position) async {
|
TextDocumentIdentifier documentId, Position position) async {
|
||||||
var symbol = await currentSymbol(documentId, position);
|
var symbol = await currentSymbol(documentId, position);
|
||||||
if (symbol != null) {
|
if (symbol != null) {
|
||||||
|
@ -379,7 +378,7 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
var symbol = await currentSymbol(documentId, position);
|
var symbol = await currentSymbol(documentId, position);
|
||||||
if (symbol != null) {
|
if (symbol != null) {
|
||||||
return symbol.usages.map((u) {
|
return symbol.usages.map((u) {
|
||||||
return new DocumentHighlight((b) {
|
return DocumentHighlight((b) {
|
||||||
b
|
b
|
||||||
..range = toRange(u.span)
|
..range = toRange(u.span)
|
||||||
..kind = u.type == SymbolUsageType.definition
|
..kind = u.type == SymbolUsageType.definition
|
||||||
|
@ -392,11 +391,11 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Hover> textDocumentHover(
|
Future<Hover?> textDocumentHover(
|
||||||
TextDocumentIdentifier documentId, Position position) async {
|
TextDocumentIdentifier documentId, Position position) async {
|
||||||
var symbol = await currentSymbol(documentId, position);
|
var symbol = await currentSymbol(documentId, position);
|
||||||
if (symbol != null) {
|
if (symbol != null) {
|
||||||
return new Hover((b) {
|
return Hover((b) {
|
||||||
b
|
b
|
||||||
..contents = symbol.span.text
|
..contents = symbol.span.text
|
||||||
..range = toRange(symbol.span);
|
..range = toRange(symbol.span);
|
||||||
|
@ -430,14 +429,13 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<WorkspaceEdit> textDocumentRename(TextDocumentIdentifier documentId,
|
Future<WorkspaceEdit> textDocumentRename(TextDocumentIdentifier documentId,
|
||||||
Position position, String newName) async {
|
Position position, String? newName) async {
|
||||||
var symbol = await currentSymbol(documentId, position);
|
var symbol = await currentSymbol(documentId, position);
|
||||||
if (symbol != null) {
|
if (symbol != null) {
|
||||||
return new WorkspaceEdit((b) {
|
return WorkspaceEdit((b) {
|
||||||
b
|
b.changes = {
|
||||||
..changes = {
|
|
||||||
symbol.name: symbol.usages.map((u) {
|
symbol.name: symbol.usages.map((u) {
|
||||||
return new TextEdit((b) {
|
return TextEdit((b) {
|
||||||
b
|
b
|
||||||
..range = toRange(u.span)
|
..range = toRange(u.span)
|
||||||
..newText = (symbol is JaelCustomElement &&
|
..newText = (symbol is JaelCustomElement &&
|
||||||
|
@ -449,8 +447,8 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return new WorkspaceEdit((b) {
|
return WorkspaceEdit((b) {
|
||||||
b..changes = {};
|
b.changes = {};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,28 +457,28 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
TextDocumentIdentifier documentId) async {
|
TextDocumentIdentifier documentId) async {
|
||||||
var analyzer = await analyzerForId(documentId);
|
var analyzer = await analyzerForId(documentId);
|
||||||
return analyzer.allDefinitions.map((symbol) {
|
return analyzer.allDefinitions.map((symbol) {
|
||||||
return new SymbolInformation((b) {
|
return SymbolInformation((b) {
|
||||||
b
|
b
|
||||||
..kind = SymbolKind.classSymbol
|
..kind = SymbolKind.classSymbol
|
||||||
..name = symbol.name
|
..name = symbol.name
|
||||||
..location = toLocation(documentId.uri, symbol.value.span);
|
..location = toLocation(documentId.uri, symbol.value!.span);
|
||||||
});
|
});
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> workspaceExecuteCommand(String command, List arguments) async {
|
Future<void> workspaceExecuteCommand(String? command, List? arguments) async {
|
||||||
// TODO: implement workspaceExecuteCommand
|
// TODO: implement workspaceExecuteCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<SymbolInformation>> workspaceSymbol(String query) async {
|
Future<List<SymbolInformation>> workspaceSymbol(String? query) async {
|
||||||
var values = <JaelObject>[];
|
var values = <JaelObject?>[];
|
||||||
|
|
||||||
await for (var file in _memRootDir.list(recursive: true)) {
|
await for (var file in _memRootDir!.list(recursive: true)) {
|
||||||
if (file is File) {
|
if (file is File) {
|
||||||
var id = new TextDocumentIdentifier((b) {
|
var id = TextDocumentIdentifier((b) {
|
||||||
b..uri = file.uri.toString();
|
b.uri = file.uri.toString();
|
||||||
});
|
});
|
||||||
var analyzer = await analyzerForId(id);
|
var analyzer = await analyzerForId(id);
|
||||||
values.addAll(analyzer.allDefinitions.map((v) => v.value));
|
values.addAll(analyzer.allDefinitions.map((v) => v.value));
|
||||||
|
@ -488,11 +486,11 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
return values.map((o) {
|
return values.map((o) {
|
||||||
return new SymbolInformation((b) {
|
return SymbolInformation((b) {
|
||||||
b
|
b
|
||||||
..name = o.name
|
..name = o!.name
|
||||||
..location = toLocation(o.span.sourceUrl.toString(), o.span)
|
..location = toLocation(o.span.sourceUrl.toString(), o.span)
|
||||||
..containerName = p.basename(o.span.sourceUrl.path)
|
..containerName = p.basename(o.span.sourceUrl!.path)
|
||||||
..kind = o is JaelCustomElement
|
..kind = o is JaelCustomElement
|
||||||
? SymbolKind.classSymbol
|
? SymbolKind.classSymbol
|
||||||
: SymbolKind.variable;
|
: SymbolKind.variable;
|
||||||
|
@ -500,7 +498,7 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<TextEdit>> textDocumentFormatting(
|
Future<List<TextEdit>?> textDocumentFormatting(
|
||||||
TextDocumentIdentifier documentId,
|
TextDocumentIdentifier documentId,
|
||||||
FormattingOptions formattingOptions) async {
|
FormattingOptions formattingOptions) async {
|
||||||
try {
|
try {
|
||||||
|
@ -510,16 +508,17 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
var document =
|
var document =
|
||||||
parseDocument(contents, sourceUrl: file.uri, onError: errors.add);
|
parseDocument(contents, sourceUrl: file.uri, onError: errors.add);
|
||||||
if (errors.isNotEmpty) return null;
|
if (errors.isNotEmpty) return null;
|
||||||
var formatter = new JaelFormatter(
|
var formatter = JaelFormatter(
|
||||||
formattingOptions.tabSize, formattingOptions.insertSpaces, 80);
|
formattingOptions.tabSize!, formattingOptions.insertSpaces, 80);
|
||||||
var formatted = formatter.apply(document);
|
var formatted = formatter.apply(document!);
|
||||||
logger.info('Original:${contents}\nFormatted:\n$formatted');
|
logger.info('Original:$contents\nFormatted:\n$formatted');
|
||||||
if (formatted.isNotEmpty) await file.writeAsString(formatted);
|
if (formatted.isNotEmpty) await file.writeAsString(formatted);
|
||||||
return [
|
return [
|
||||||
new TextEdit((b) {
|
TextEdit((b) {
|
||||||
b
|
b
|
||||||
..newText = formatted
|
..newText = formatted
|
||||||
..range = document == null ? emptyRange() : toRange(document.span);
|
..range = toRange(document
|
||||||
|
.span); //document == null ? emptyRange() : toRange(document.span);
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
|
@ -535,7 +534,7 @@ class JaelLanguageServer extends LanguageServer {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
// TODO: implement showMessages
|
// TODO: implement showMessages
|
||||||
Stream<ShowMessageParams> get showMessages => null;
|
Stream<ShowMessageParams>? get showMessages => null;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class DiagnosticSeverity {
|
abstract class DiagnosticSeverity {
|
||||||
|
@ -543,14 +542,14 @@ abstract class DiagnosticSeverity {
|
||||||
}
|
}
|
||||||
|
|
||||||
class FormattingOptions {
|
class FormattingOptions {
|
||||||
final num tabSize;
|
final num? tabSize;
|
||||||
|
|
||||||
final bool insertSpaces;
|
final bool? insertSpaces;
|
||||||
|
|
||||||
FormattingOptions(this.tabSize, this.insertSpaces);
|
FormattingOptions(this.tabSize, this.insertSpaces);
|
||||||
|
|
||||||
factory FormattingOptions.fromJson(Map json) {
|
factory FormattingOptions.fromJson(Map json) {
|
||||||
return new FormattingOptions(
|
return FormattingOptions(
|
||||||
json['tabSize'] as num, json['insertSpaces'] as bool);
|
json['tabSize'] as num?, json['insertSpaces'] as bool?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,36 @@
|
||||||
name: jael_language_server
|
name: jael_language_server
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
description: Language Server Protocol implementation for the Jael templating engine.
|
description: Language Server Protocol implementation for the Jael templating engine.
|
||||||
author: Tobe Osakwe <thosakwe@gmail.com>
|
|
||||||
homepage: https://github.com/angel-dart/vscode
|
homepage: https://github.com/angel-dart/vscode
|
||||||
|
publish_to: none
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.10.0 <2.12.0'
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
args: ^1.0.0
|
args: ^2.1.1
|
||||||
# dart_language_server: ^0.1.16
|
# dart_language_server: ^0.1.16
|
||||||
file: ^5.0.0
|
file: ^6.1.2
|
||||||
io: ^0.3.2
|
io: ^1.0.0
|
||||||
jael: #^2.0.0
|
jael:
|
||||||
path: ../jael
|
git:
|
||||||
jael_preprocessor: #^2.0.0
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
path: ../jael_preprocessor
|
ref: sdk-2.12.x_nnbd
|
||||||
json_rpc_2: ^2.0.0
|
path: packages/jael/jael
|
||||||
logging: ^0.11.3
|
jael_preprocessor:
|
||||||
path: ^1.0.0
|
git:
|
||||||
source_span: ^1.0.0
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
string_scanner: ^1.0.0
|
ref: sdk-2.12.x_nnbd
|
||||||
symbol_table: ^2.0.0
|
path: packages/jael/jael_preprocessor
|
||||||
|
json_rpc_2: ^3.0.1
|
||||||
|
logging: ^1.0.1
|
||||||
|
path: ^1.8.0
|
||||||
|
source_span: ^1.8.1
|
||||||
|
string_scanner: ^1.1.0
|
||||||
|
symbol_table:
|
||||||
|
git:
|
||||||
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
|
ref: sdk-2.12.x_nnbd
|
||||||
|
path: packages/symbol_table
|
||||||
|
pedantic: ^1.11.0
|
||||||
executables:
|
executables:
|
||||||
jael_language_server: jael_language_server
|
jael_language_server: jael_language_server
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
MIT License (MIT)
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2021 dukefirehawk.com
|
Copyright (c) 2017 The Angel Framework
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
@ -5,18 +5,18 @@ part 'stateful.g.dart';
|
||||||
void main() {}
|
void main() {}
|
||||||
|
|
||||||
class _AppState {
|
class _AppState {
|
||||||
final int ticks;
|
final int? ticks;
|
||||||
|
|
||||||
_AppState({this.ticks});
|
_AppState({this.ticks});
|
||||||
|
|
||||||
_AppState copyWith({int ticks}) {
|
_AppState copyWith({int? ticks}) {
|
||||||
return _AppState(ticks: ticks ?? this.ticks);
|
return _AppState(ticks: ticks ?? this.ticks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Jael(template: '<div>Tick count: {{state.ticks}}</div>')
|
@Jael(template: '<div>Tick count: {{state.ticks}}</div>')
|
||||||
class StatefulApp extends Component<_AppState> with _StatefulAppJaelTemplate {
|
class StatefulApp extends Component<_AppState> with _StatefulAppJaelTemplate {
|
||||||
Timer _timer;
|
Timer? _timer;
|
||||||
|
|
||||||
StatefulApp() {
|
StatefulApp() {
|
||||||
state = _AppState(ticks: 0);
|
state = _AppState(ticks: 0);
|
||||||
|
@ -27,6 +27,6 @@ class StatefulApp extends Component<_AppState> with _StatefulAppJaelTemplate {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void beforeDestroy() {
|
void beforeDestroy() {
|
||||||
_timer.cancel();
|
_timer!.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ part of 'stateful.dart';
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
abstract class _StatefulAppJaelTemplate implements Component<_AppState> {
|
abstract class _StatefulAppJaelTemplate implements Component<_AppState> {
|
||||||
Timer get _timer;
|
Timer? get _timer;
|
||||||
void beforeDestroy();
|
void beforeDestroy();
|
||||||
@override
|
@override
|
||||||
DomNode render() {
|
DomNode render() {
|
||||||
|
|
|
@ -19,7 +19,7 @@ class MyApp extends Component with _MyAppJaelTemplate {}
|
||||||
</div>
|
</div>
|
||||||
''')
|
''')
|
||||||
class LabeledInput extends Component with _LabeledInputJaelTemplate {
|
class LabeledInput extends Component with _LabeledInputJaelTemplate {
|
||||||
final String name;
|
final String? name;
|
||||||
|
|
||||||
LabeledInput({this.name});
|
LabeledInput({this.name});
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ abstract class _MyAppJaelTemplate implements Component<dynamic> {
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class _LabeledInputJaelTemplate implements Component<dynamic> {
|
abstract class _LabeledInputJaelTemplate implements Component<dynamic> {
|
||||||
String get name;
|
String? get name;
|
||||||
@override
|
@override
|
||||||
DomNode render() {
|
DomNode render() {
|
||||||
return h('div', {}, [
|
return h('div', {}, [
|
||||||
|
@ -27,7 +27,7 @@ abstract class _LabeledInputJaelTemplate implements Component<dynamic> {
|
||||||
h('br', {}, []),
|
h('br', {}, []),
|
||||||
h('input', {
|
h('input', {
|
||||||
'name': name,
|
'name': name,
|
||||||
'placeholder': "Enter " + name + "...",
|
'placeholder': "Enter " + name! + "...",
|
||||||
'type': "text"
|
'type': "text"
|
||||||
}, [])
|
}, [])
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -21,7 +21,7 @@ class JaelComponentGenerator extends GeneratorForAnnotation<Jael> {
|
||||||
Element element, ConstantReader annotation, BuildStep buildStep) async {
|
Element element, ConstantReader annotation, BuildStep buildStep) async {
|
||||||
if (element is ClassElement) {
|
if (element is ClassElement) {
|
||||||
// Load the template
|
// Load the template
|
||||||
String templateString;
|
String? templateString;
|
||||||
var inputId = buildStep.inputId;
|
var inputId = buildStep.inputId;
|
||||||
var ann = Jael(
|
var ann = Jael(
|
||||||
template: annotation.peek('template')?.stringValue,
|
template: annotation.peek('template')?.stringValue,
|
||||||
|
@ -47,10 +47,10 @@ class JaelComponentGenerator extends GeneratorForAnnotation<Jael> {
|
||||||
|
|
||||||
var fs = BuildFileSystem(buildStep, inputId.package);
|
var fs = BuildFileSystem(buildStep, inputId.package);
|
||||||
var errors = <jael.JaelError>[];
|
var errors = <jael.JaelError>[];
|
||||||
var doc = await jael.parseDocument(templateString,
|
var doc = await jael.parseDocument(templateString!,
|
||||||
sourceUrl: inputId.uri, asDSX: ann.asDsx, onError: errors.add);
|
sourceUrl: inputId.uri, asDSX: ann.asDsx!, onError: errors.add);
|
||||||
if (errors.isEmpty) {
|
if (errors.isEmpty) {
|
||||||
doc = await jael.resolve(doc, fs.file(inputId.uri).parent,
|
doc = await jael.resolve(doc!, fs.file(inputId.uri).parent,
|
||||||
onError: errors.add);
|
onError: errors.add);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ class JaelComponentGenerator extends GeneratorForAnnotation<Jael> {
|
||||||
..returns = refer('DomNode')
|
..returns = refer('DomNode')
|
||||||
..annotations.add(refer('override'))
|
..annotations.add(refer('override'))
|
||||||
..body = Block((b) {
|
..body = Block((b) {
|
||||||
var result = compileElementChild(doc.root);
|
var result = compileElementChild(doc!.root);
|
||||||
b.addExpression(result.returned);
|
b.addExpression(result.returned);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -123,7 +123,7 @@ class JaelComponentGenerator extends GeneratorForAnnotation<Jael> {
|
||||||
for (var attr in child.attributes) {
|
for (var attr in child.attributes) {
|
||||||
attrs[attr.name] = attr.value == null
|
attrs[attr.name] = attr.value == null
|
||||||
? literalTrue
|
? literalTrue
|
||||||
: CodeExpression(Code(attr.value.span.text));
|
: CodeExpression(Code(attr.value!.span.text));
|
||||||
}
|
}
|
||||||
|
|
||||||
var tagName = child.tagName.name;
|
var tagName = child.tagName.name;
|
||||||
|
|
|
@ -10,9 +10,9 @@ import 'package:file/file.dart';
|
||||||
import 'package:path/src/context.dart';
|
import 'package:path/src/context.dart';
|
||||||
|
|
||||||
/// Converts a [DartType] to a [TypeReference].
|
/// Converts a [DartType] to a [TypeReference].
|
||||||
TypeReference convertTypeReference(DartType t) {
|
TypeReference convertTypeReference(DartType? t) {
|
||||||
return new TypeReference((b) {
|
return new TypeReference((b) {
|
||||||
b..symbol = t.name;
|
b..symbol = t!.name;
|
||||||
|
|
||||||
if (t is InterfaceType) {
|
if (t is InterfaceType) {
|
||||||
b.types.addAll(t.typeArguments.map(convertTypeReference));
|
b.types.addAll(t.typeArguments.map(convertTypeReference));
|
||||||
|
@ -35,7 +35,7 @@ Parameter convertParameter(ParameterElement e) {
|
||||||
..type = convertTypeReference(e.type)
|
..type = convertTypeReference(e.type)
|
||||||
..named = e.isNamed
|
..named = e.isNamed
|
||||||
..defaultTo =
|
..defaultTo =
|
||||||
e.defaultValueCode == null ? null : Code(e.defaultValueCode);
|
e.defaultValueCode == null ? null : Code(e.defaultValueCode!);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,11 +68,11 @@ class BuildFileSystem extends FileSystem {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Directory directory(path) {
|
Directory directory(path) {
|
||||||
String p;
|
late String p;
|
||||||
if (path is String)
|
if (path is String)
|
||||||
p = path;
|
p = path;
|
||||||
else if (path is Uri)
|
else if (path is Uri)
|
||||||
p = p.toString();
|
p = path.toString(); //p.toString();
|
||||||
else if (path is FileSystemEntity)
|
else if (path is FileSystemEntity)
|
||||||
p = path.path;
|
p = path.path;
|
||||||
else
|
else
|
||||||
|
@ -82,11 +82,11 @@ class BuildFileSystem extends FileSystem {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
File file(path) {
|
File file(path) {
|
||||||
String p;
|
late String p;
|
||||||
if (path is String)
|
if (path is String)
|
||||||
p = path;
|
p = path;
|
||||||
else if (path is Uri)
|
else if (path is Uri)
|
||||||
p = p.toString();
|
p = path.toString(); // p.toString();
|
||||||
else if (path is FileSystemEntity)
|
else if (path is FileSystemEntity)
|
||||||
p = path.path;
|
p = path.path;
|
||||||
else
|
else
|
||||||
|
@ -192,7 +192,7 @@ class BuildSystemFile extends File {
|
||||||
throw _unsupported();
|
throw _unsupported();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<List<int>> openRead([int start, int end]) => throw _unsupported();
|
Stream<List<int>> openRead([int? start, int? end]) => throw _unsupported();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
RandomAccessFile openSync({FileMode mode = FileMode.read}) =>
|
RandomAccessFile openSync({FileMode mode = FileMode.read}) =>
|
||||||
|
@ -347,10 +347,10 @@ class BuildSystemDirectory extends Directory {
|
||||||
void createSync({bool recursive = false}) => throw _unsupported();
|
void createSync({bool recursive = false}) => throw _unsupported();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Directory> createTemp([String prefix]) => throw _unsupported();
|
Future<Directory> createTemp([String? prefix]) => throw _unsupported();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Directory createTempSync([String prefix]) => throw _unsupported();
|
Directory createTempSync([String? prefix]) => throw _unsupported();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<FileSystemEntity> delete({bool recursive = false}) =>
|
Future<FileSystemEntity> delete({bool recursive = false}) =>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'dom_builder.dart';
|
||||||
import 'dom_node.dart';
|
import 'dom_node.dart';
|
||||||
|
|
||||||
abstract class BuilderNode extends DomNode {
|
abstract class BuilderNode extends DomNode {
|
||||||
DomBuilderElement<T> build<T>(DomBuilder<T> dom);
|
DomBuilderElement<T>? build<T>(DomBuilder<T> dom);
|
||||||
|
|
||||||
void destroy<T>(DomBuilderElement<T> el);
|
void destroy<T>(DomBuilderElement<T> el);
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ class _Text extends BuilderNode {
|
||||||
_Text(this.text);
|
_Text(this.text);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
DomBuilderElement<T> build<T>(DomBuilder<T> dom) {
|
DomBuilderElement<T>? build<T>(DomBuilder<T> dom) {
|
||||||
dom.text(text);
|
dom.text(text);
|
||||||
// TODO: implement build
|
// TODO: implement build
|
||||||
return null;
|
return null;
|
||||||
|
@ -41,7 +41,7 @@ class _H extends BuilderNode {
|
||||||
_H(this.tagName, this.props, this.children);
|
_H(this.tagName, this.props, this.children);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
DomBuilderElement<T> build<T>(DomBuilder<T> dom) {
|
DomBuilderElement<T>? build<T>(DomBuilder<T> dom) {
|
||||||
// TODO: implement build
|
// TODO: implement build
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import 'dom_node.dart';
|
import 'dom_node.dart';
|
||||||
|
|
||||||
abstract class Component<State> extends DomNode {
|
abstract class Component<State> extends DomNode {
|
||||||
State state;
|
late State state;
|
||||||
|
|
||||||
DomNode render();
|
DomNode render();
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ abstract class DomBuilder<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class DomBuilderElement<T> extends DomBuilder<T> {
|
abstract class DomBuilderElement<T> extends DomBuilder<T> {
|
||||||
void attr(String name, [String value]);
|
void attr(String name, [String? value]);
|
||||||
|
|
||||||
void attrs(Map<String, String> map);
|
void attrs(Map<String, String> map);
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,19 +1,19 @@
|
||||||
/// A annotation for components that source-gen their `render()` methods.
|
/// A annotation for components that source-gen their `render()` methods.
|
||||||
class Jael {
|
class Jael {
|
||||||
/// The raw template.
|
/// The raw template.
|
||||||
final String template;
|
final String? template;
|
||||||
|
|
||||||
/// The path to a [template].
|
/// The path to a [template].
|
||||||
final String templateUrl;
|
final String? templateUrl;
|
||||||
|
|
||||||
/// Whether to parse the [template] as `DSX`.
|
/// Whether to parse the [template] as `DSX`.
|
||||||
final bool asDsx;
|
final bool? asDsx;
|
||||||
|
|
||||||
const Jael({this.template, this.templateUrl, this.asDsx});
|
const Jael({this.template, this.templateUrl, this.asDsx});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shorthand for enabling `DSX` syntax when using a [Jael] annotation.
|
/// Shorthand for enabling `DSX` syntax when using a [Jael] annotation.
|
||||||
class Dsx extends Jael {
|
class Dsx extends Jael {
|
||||||
const Dsx({String template, String templateUrl})
|
const Dsx({String? template, String? templateUrl})
|
||||||
: super(template: template, templateUrl: templateUrl, asDsx: true);
|
: super(template: template, templateUrl: templateUrl, asDsx: true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,25 @@
|
||||||
name: jael_web
|
name: jael_web
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
description: Experimental virtual DOM/SPA engine built on Jael. Supports SSR.
|
description: Experimental virtual DOM/SPA engine built on Jael. Supports SSR.
|
||||||
|
publish_to: none
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.10.0 <2.12.0'
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
build: ^1.0.0
|
build: ^2.0.2
|
||||||
build_config: ^0.3.0
|
build_config: ^1.0.0
|
||||||
code_builder: ^3.0.0
|
code_builder: ^4.0.0
|
||||||
jael: #^2.0.0
|
jael:
|
||||||
path: ../jael
|
git:
|
||||||
jael_preprocessor: #^2.0.0
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
path: ../jael_preprocessor
|
ref: sdk-2.12.x_nnbd
|
||||||
source_gen: ^0.9.0
|
path: packages/jael/jael
|
||||||
|
jael_preprocessor:
|
||||||
|
git:
|
||||||
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
|
ref: sdk-2.12.x_nnbd
|
||||||
|
path: packages/jael/jael_preprocessor
|
||||||
|
source_gen: ^1.0.2
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^1.0.0
|
build_runner: ^2.0.4
|
||||||
build_web_compilers: ^1.0.0
|
build_web_compilers: ^3.0.0
|
||||||
pedantic: ^1.0.0
|
pedantic: ^1.11.1
|
12
packages/jinja/AUTHORS.md
Normal file
12
packages/jinja/AUTHORS.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Primary Authors
|
||||||
|
===============
|
||||||
|
|
||||||
|
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
||||||
|
|
||||||
|
Thomas is the current maintainer of the code base. He has refactored and migrated the
|
||||||
|
code base to support NNBD.
|
||||||
|
|
||||||
|
* __[Tobe O](thosakwe@gmail.com)__
|
||||||
|
|
||||||
|
Tobe has written much of the original code prior to NNBD migration. He has moved on and
|
||||||
|
is no longer involved with the project.
|
|
@ -1,3 +1,6 @@
|
||||||
## 1.0.0
|
# 2.0.0
|
||||||
|
* Migrated to support Dart SDK 2.12.x NNBD
|
||||||
|
|
||||||
|
# 1.0.0
|
||||||
|
|
||||||
- Initial version, created by Stagehand
|
- Initial version, created by Stagehand
|
||||||
|
|
|
@ -11,7 +11,7 @@ import 'package:angel_framework/http.dart';
|
||||||
import 'package:angel_jinja/angel_jinja.dart';
|
import 'package:angel_jinja/angel_jinja.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
|
|
||||||
main() async {
|
void main() async {
|
||||||
var app = Angel();
|
var app = Angel();
|
||||||
var http = AngelHttp(app);
|
var http = AngelHttp(app);
|
||||||
var viewsDir = p.join(
|
var viewsDir = p.join(
|
||||||
|
|
|
@ -4,7 +4,7 @@ import 'package:angel_framework/http.dart';
|
||||||
import 'package:angel_jinja/angel_jinja.dart';
|
import 'package:angel_jinja/angel_jinja.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
|
|
||||||
main() async {
|
void main() async {
|
||||||
var app = Angel();
|
var app = Angel();
|
||||||
var http = AngelHttp(app);
|
var http = AngelHttp(app);
|
||||||
var viewsDir = p.join(
|
var viewsDir = p.join(
|
||||||
|
|
|
@ -9,45 +9,45 @@ import 'package:jinja/jinja.dart';
|
||||||
/// All options other than [createLoader] are passed to either [FileSystemLoader]
|
/// All options other than [createLoader] are passed to either [FileSystemLoader]
|
||||||
/// or [Environment].
|
/// or [Environment].
|
||||||
AngelConfigurer jinja({
|
AngelConfigurer jinja({
|
||||||
Iterable<String> ext = const ['html'],
|
Set<String> ext = const {'html'},
|
||||||
String path = 'lib/src/templates',
|
String path = 'lib/src/templates',
|
||||||
bool followLinks = true,
|
bool followLinks = true,
|
||||||
String stmtOpen = '{%',
|
String blockStart = '{%',
|
||||||
String stmtClose = '%}',
|
String blockEnd = '%}',
|
||||||
String varOpen = '{{',
|
String varOpen = '{{',
|
||||||
String varClose = '}}',
|
String varClose = '}}',
|
||||||
String commentOpen = '{#',
|
String commentStart = '{#',
|
||||||
String commentClose = '#}',
|
String commentEnd = '#}',
|
||||||
defaultValue,
|
defaultValue,
|
||||||
bool autoReload = true,
|
//bool autoReload = true,
|
||||||
Map<String, Function> filters = const <String, Function>{},
|
Map<String, Function> filters = const <String, Function>{},
|
||||||
Map<String, Function> tests = const <String, Function>{},
|
Map<String, Function> tests = const <String, Function>{},
|
||||||
Loader Function() createLoader,
|
Loader Function()? createLoader,
|
||||||
}) {
|
}) {
|
||||||
return (app) {
|
return (app) {
|
||||||
createLoader ??= () {
|
createLoader ??= () {
|
||||||
return FileSystemLoader(
|
return FileSystemLoader(
|
||||||
ext: ext.toList(),
|
extensions: ext,
|
||||||
path: path,
|
path: path,
|
||||||
followLinks: followLinks,
|
followLinks: followLinks,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
var env = Environment(
|
var env = Environment(
|
||||||
loader: createLoader(),
|
loader: createLoader!(),
|
||||||
stmtOpen: stmtOpen,
|
blockStart: blockStart,
|
||||||
stmtClose: stmtClose,
|
blockEnd: blockEnd,
|
||||||
varOpen: varOpen,
|
variableStart: varOpen,
|
||||||
varClose: varClose,
|
variableEnd: varClose,
|
||||||
commentOpen: commentOpen,
|
commentStart: commentStart,
|
||||||
commentClose: commentClose,
|
commentEnd: commentEnd,
|
||||||
//defaultValue: defaultValue,
|
//defaultValue: defaultValue,
|
||||||
autoReload: autoReload,
|
//autoReload: autoReload,
|
||||||
filters: filters,
|
filters: filters,
|
||||||
tests: tests,
|
tests: tests,
|
||||||
);
|
);
|
||||||
|
|
||||||
app.viewGenerator = (path, [values]) {
|
app.viewGenerator = (path, [values]) {
|
||||||
return env.getTemplate(path).render(values);
|
return env.getTemplate(path).render(values) as String;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,23 @@
|
||||||
name: angel_jinja
|
name: angel_jinja
|
||||||
|
version: 2.0.0
|
||||||
description: Angel support for the Jinja2 templating engine, ported from Python to Dart.
|
description: Angel support for the Jinja2 templating engine, ported from Python to Dart.
|
||||||
version: 1.0.0-rc.0
|
|
||||||
homepage: https://github.com/angel-dart/jinja
|
homepage: https://github.com/angel-dart/jinja
|
||||||
author: Tobe O <thosakwe@gmail.com>
|
publish_to: none
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.10.0 <2.12.0'
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
angel_framework: #^2.0.0-alpha
|
angel_framework:
|
||||||
path: ../framework
|
git:
|
||||||
jinja: ^0.0.4
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
|
ref: sdk-2.12.x_nnbd
|
||||||
|
path: packages/framework
|
||||||
|
jinja: ^0.3.1
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
angel_test: #^2.0.0
|
angel_test:
|
||||||
path: ../test
|
git:
|
||||||
path: ^1.0.0
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
pedantic: ^1.0.0
|
ref: sdk-2.12.x_nnbd
|
||||||
test: ^1.15.7
|
path: packages/test
|
||||||
|
path: ^1.8.0
|
||||||
|
pedantic: ^1.11.0
|
||||||
|
test: ^1.17.0
|
||||||
|
|
12
packages/markdown/AUTHORS.md
Normal file
12
packages/markdown/AUTHORS.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Primary Authors
|
||||||
|
===============
|
||||||
|
|
||||||
|
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
||||||
|
|
||||||
|
Thomas is the current maintainer of the code base. He has refactored and migrated the
|
||||||
|
code base to support NNBD.
|
||||||
|
|
||||||
|
* __[Tobe O](thosakwe@gmail.com)__
|
||||||
|
|
||||||
|
Tobe has written much of the original code prior to NNBD migration. He has moved on and
|
||||||
|
is no longer involved with the project.
|
|
@ -1,3 +1,6 @@
|
||||||
|
# 3.0.0
|
||||||
|
* Migrated to support Dart SDK 2.12.x NNBD
|
||||||
|
|
||||||
# 2.0.0
|
# 2.0.0
|
||||||
* Angel 2 + Dart 2 updates.
|
* Angel 2 + Dart 2 updates.
|
||||||
* Use `package:file`.
|
* Use `package:file`.
|
|
@ -5,7 +5,7 @@ import 'package:angel_framework/http.dart';
|
||||||
import 'package:angel_markdown/angel_markdown.dart';
|
import 'package:angel_markdown/angel_markdown.dart';
|
||||||
import 'package:file/local.dart';
|
import 'package:file/local.dart';
|
||||||
|
|
||||||
main() async {
|
void main() async {
|
||||||
var app = await createServer();
|
var app = await createServer();
|
||||||
var http = AngelHttp(app);
|
var http = AngelHttp(app);
|
||||||
var server = await http.startServer(InternetAddress.loopbackIPv4, 3000);
|
var server = await http.startServer(InternetAddress.loopbackIPv4, 3000);
|
||||||
|
@ -14,7 +14,7 @@ main() async {
|
||||||
|
|
||||||
Future<Angel> createServer() async {
|
Future<Angel> createServer() async {
|
||||||
// Create a new server, and install the Markdown renderer.
|
// Create a new server, and install the Markdown renderer.
|
||||||
var app = new Angel();
|
var app = Angel();
|
||||||
var fs = LocalFileSystem();
|
var fs = LocalFileSystem();
|
||||||
await app
|
await app
|
||||||
.configure(markdown(fs.directory('views'), template: (content, locals) {
|
.configure(markdown(fs.directory('views'), template: (content, locals) {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import 'package:angel_framework/angel_framework.dart';
|
||||||
import 'package:file/file.dart';
|
import 'package:file/file.dart';
|
||||||
import 'package:markdown/markdown.dart';
|
import 'package:markdown/markdown.dart';
|
||||||
|
|
||||||
final RegExp _braces = new RegExp(r'@?{{(((\\})|([^}]))+)}}');
|
final RegExp _braces = RegExp(r'@?{{(((\\})|([^}]))+)}}');
|
||||||
|
|
||||||
/// Configures an [Angel] instance to render Markdown templates from the specified [viewsDirectory].
|
/// Configures an [Angel] instance to render Markdown templates from the specified [viewsDirectory].
|
||||||
///
|
///
|
||||||
|
@ -18,7 +18,8 @@ AngelConfigurer markdown(
|
||||||
Directory viewsDirectory, {
|
Directory viewsDirectory, {
|
||||||
String extension,
|
String extension,
|
||||||
ExtensionSet extensionSet,
|
ExtensionSet extensionSet,
|
||||||
FutureOr<String> template(String content, Map<String, dynamic> locals),
|
FutureOr<String> Function(String content, Map<String, dynamic> locals)
|
||||||
|
template,
|
||||||
}) {
|
}) {
|
||||||
extension ??= '.md';
|
extension ??= '.md';
|
||||||
extensionSet ??= ExtensionSet.gitHubWeb;
|
extensionSet ??= ExtensionSet.gitHubWeb;
|
||||||
|
@ -40,9 +41,10 @@ AngelConfigurer markdown(
|
||||||
var split = expr.split('.');
|
var split = expr.split('.');
|
||||||
var root = split[0];
|
var root = split[0];
|
||||||
|
|
||||||
if (locals?.containsKey(root) != true)
|
if (locals?.containsKey(root) != true) {
|
||||||
throw new UnimplementedError(
|
throw UnimplementedError(
|
||||||
'Expected a local named "$root", but none was provided. Expression text: "$text"');
|
'Expected a local named "$root", but none was provided. Expression text: "$text"');
|
||||||
|
}
|
||||||
|
|
||||||
return _resolveDotNotation(split, locals[root]).toString();
|
return _resolveDotNotation(split, locals[root]).toString();
|
||||||
}
|
}
|
||||||
|
@ -55,13 +57,13 @@ AngelConfigurer markdown(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_resolveDotNotation(List<String> split, target) {
|
dynamic _resolveDotNotation(List<String> split, target) {
|
||||||
if (split.length == 1) return target;
|
if (split.length == 1) return target;
|
||||||
|
|
||||||
InstanceMirror mirror = reflect(target);
|
var mirror = reflect(target);
|
||||||
|
|
||||||
for (int i = 1; i < split.length; i++) {
|
for (var i = 1; i < split.length; i++) {
|
||||||
mirror = mirror.getField(new Symbol(split[i]));
|
mirror = mirror.getField(Symbol(split[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return mirror.reflectee;
|
return mirror.reflectee;
|
||||||
|
|
|
@ -1,17 +1,23 @@
|
||||||
name: angel_markdown
|
name: angel_markdown
|
||||||
version: 2.0.0
|
version: 3.0.0
|
||||||
description: Angel Markdown view generator. Write static sites, with no build step.
|
description: Angel Markdown view generator. Write static sites, with no build step.
|
||||||
author: Tobe O <thosakwe@gmail.com>
|
|
||||||
homepage: https://github.com/angel-dart/markdown
|
homepage: https://github.com/angel-dart/markdown
|
||||||
|
publish_to: none
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.10.0 <2.12.0"
|
sdk: ">=2.10.0 <3.0.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
angel_framework: #^2.0.0-alpha
|
angel_framework:
|
||||||
path: ../framework
|
git:
|
||||||
file: ^5.0.0
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
markdown: ^2.0.0
|
ref: sdk-2.12.x_nnbd
|
||||||
|
path: packages/framework
|
||||||
|
file: ^6.1.2
|
||||||
|
markdown: ^4.0.0
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
angel_test: #^2.0.0
|
angel_test:
|
||||||
path: ../test
|
git:
|
||||||
pedantic: ^1.0.0
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
test: ^1.15.7
|
ref: sdk-2.12.x_nnbd
|
||||||
|
path: packages/test
|
||||||
|
pedantic: ^1.11.0
|
||||||
|
test: ^1.17.0
|
||||||
|
|
12
packages/mustache/AUTHORS.md
Normal file
12
packages/mustache/AUTHORS.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Primary Authors
|
||||||
|
===============
|
||||||
|
|
||||||
|
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
||||||
|
|
||||||
|
Thomas is the current maintainer of the code base. He has refactored and migrated the
|
||||||
|
code base to support NNBD.
|
||||||
|
|
||||||
|
* __[Tobe O](thosakwe@gmail.com)__
|
||||||
|
|
||||||
|
Tobe has written much of the original code prior to NNBD migration. He has moved on and
|
||||||
|
is no longer involved with the project.
|
|
@ -1,2 +1,6 @@
|
||||||
|
# 3.0.0
|
||||||
|
* Migrated to support Dart SDK 2.12.x NNBD
|
||||||
|
* Replaced `mustache4dart` with `mustache_template`
|
||||||
|
|
||||||
# 2.0.0
|
# 2.0.0
|
||||||
* Angel 2 and Dart 2 support.
|
* Angel 2 and Dart 2 support.
|
|
@ -1,2 +1,4 @@
|
||||||
|
include: package:pedantic/analysis_options.yaml
|
||||||
analyzer:
|
analyzer:
|
||||||
strong-mode: true
|
strong-mode:
|
||||||
|
implicit-casts: false
|
|
@ -3,9 +3,9 @@ import 'package:angel_mustache/angel_mustache.dart';
|
||||||
import 'package:file/file.dart';
|
import 'package:file/file.dart';
|
||||||
import 'package:file/local.dart';
|
import 'package:file/local.dart';
|
||||||
|
|
||||||
const FileSystem fs = const LocalFileSystem();
|
const FileSystem fs = LocalFileSystem();
|
||||||
|
|
||||||
configureServer(Angel app) async {
|
void configureServer(Angel app) async {
|
||||||
// Run the plug-in
|
// Run the plug-in
|
||||||
await app.configure(mustache(fs.directory('views')));
|
await app.configure(mustache(fs.directory('views')));
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,38 @@
|
||||||
library angel_mustache;
|
library angel_mustache;
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
import 'package:file/file.dart';
|
import 'package:file/file.dart';
|
||||||
import 'package:mustache4dart/mustache4dart.dart' show render;
|
import 'package:mustache_template/mustache_template.dart' as viewer;
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
import 'src/cache.dart';
|
import 'src/cache.dart';
|
||||||
import 'src/mustache_context.dart';
|
import 'src/mustache_context.dart';
|
||||||
|
|
||||||
mustache(Directory viewsDirectory,
|
Future Function(Angel app) mustache(Directory viewsDirectory,
|
||||||
{String fileExtension: '.mustache', String partialsPath: './partials'}) {
|
{String fileExtension = '.mustache', String partialsPath = './partials'}) {
|
||||||
Directory partialsDirectory = viewsDirectory.fileSystem
|
var partialsDirectory = viewsDirectory.fileSystem
|
||||||
.directory(p.join(p.fromUri(viewsDirectory.uri), partialsPath));
|
.directory(p.join(p.fromUri(viewsDirectory.uri), partialsPath));
|
||||||
|
|
||||||
MustacheContext context =
|
var context =
|
||||||
new MustacheContext(viewsDirectory, partialsDirectory, fileExtension);
|
MustacheContext(viewsDirectory, partialsDirectory, fileExtension);
|
||||||
|
|
||||||
MustacheViewCache cache = new MustacheViewCache(context);
|
var cache = MustacheViewCache(context);
|
||||||
|
|
||||||
return (Angel app) async {
|
return (Angel app) async {
|
||||||
app.viewGenerator = (String name, [Map data]) async {
|
app.viewGenerator = (String name, [Map? data]) async {
|
||||||
var partialsProvider;
|
//var partialsProvider;
|
||||||
partialsProvider = (String name) {
|
var partialsProvider = (String name) {
|
||||||
String template = cache.getPartialSync(name, app);
|
var template = cache.getPartialSync(name, app)!;
|
||||||
return render(template, data ?? {}, partial: partialsProvider);
|
//return render(template, data ?? {}, partial: partialsProvider);
|
||||||
|
return viewer.Template(template, name: name);
|
||||||
};
|
};
|
||||||
|
|
||||||
String viewTemplate = await cache.getView(name, app);
|
var viewTemplate = await (cache.getView(name, app));
|
||||||
return await render(viewTemplate, data ?? {}, partial: partialsProvider);
|
//return await render(viewTemplate, data ?? {}, partial: partialsProvider);
|
||||||
|
var t = viewer.Template(viewTemplate ?? '',
|
||||||
|
partialResolver: partialsProvider);
|
||||||
|
return t.renderString(data ?? {});
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,54 +6,57 @@ import 'package:angel_framework/angel_framework.dart';
|
||||||
import 'package:angel_mustache/src/mustache_context.dart';
|
import 'package:angel_mustache/src/mustache_context.dart';
|
||||||
|
|
||||||
class MustacheViewCache {
|
class MustacheViewCache {
|
||||||
/**
|
/// The context for which views and partials are
|
||||||
* The context for which views and partials are
|
/// served from.
|
||||||
* served from.
|
MustacheContext? context;
|
||||||
*/
|
|
||||||
MustacheContext context;
|
|
||||||
|
|
||||||
HashMap<String, String> viewCache = new HashMap();
|
HashMap<String, String> viewCache = HashMap();
|
||||||
HashMap<String, String> partialCache = new HashMap();
|
HashMap<String, String> partialCache = HashMap();
|
||||||
|
|
||||||
MustacheViewCache([this.context]);
|
MustacheViewCache([this.context]);
|
||||||
|
|
||||||
Future<String> getView(String viewName, Angel app) async {
|
Future<String?> getView(String viewName, Angel app) async {
|
||||||
if (app.isProduction) {
|
if (app.environment.isProduction) {
|
||||||
if (viewCache.containsKey(viewName)) {
|
if (viewCache.containsKey(viewName)) {
|
||||||
return viewCache[viewName];
|
return viewCache[viewName];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File viewFile = context.resolveView(viewName);
|
var viewFile = context?.resolveView(viewName);
|
||||||
|
if (viewFile == null) {
|
||||||
|
throw FileSystemException('View "$viewName" was not found.', 'null');
|
||||||
|
}
|
||||||
|
|
||||||
if (viewFile.existsSync()) {
|
if (viewFile.existsSync()) {
|
||||||
String viewTemplate = await viewFile.readAsString();
|
var viewTemplate = await viewFile.readAsString();
|
||||||
if (app.isProduction) {
|
if (app.environment.isProduction) {
|
||||||
this.viewCache[viewName] = viewTemplate;
|
viewCache[viewName] = viewTemplate;
|
||||||
}
|
}
|
||||||
return viewTemplate;
|
return viewTemplate;
|
||||||
} else
|
} else {
|
||||||
throw new FileSystemException(
|
throw FileSystemException(
|
||||||
'View "$viewName" was not found.', viewFile.path);
|
'View "$viewName" was not found.', viewFile.path);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String getPartialSync(String partialName, Angel app) {
|
String? getPartialSync(String partialName, Angel app) {
|
||||||
if (app.isProduction) {
|
if (app.environment.isProduction) {
|
||||||
if (partialCache.containsKey(partialName)) {
|
if (partialCache.containsKey(partialName)) {
|
||||||
return partialCache[partialName];
|
return partialCache[partialName];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File partialFile = context.resolvePartial(partialName);
|
var partialFile = context!.resolvePartial(partialName);
|
||||||
|
|
||||||
if (partialFile.existsSync()) {
|
if (partialFile.existsSync()) {
|
||||||
String partialTemplate = partialFile.readAsStringSync();
|
var partialTemplate = partialFile.readAsStringSync();
|
||||||
if (app.isProduction) {
|
if (app.environment.isProduction) {
|
||||||
this.partialCache[partialName] = partialTemplate;
|
partialCache[partialName] = partialTemplate;
|
||||||
}
|
}
|
||||||
return partialTemplate;
|
return partialTemplate;
|
||||||
} else
|
} else {
|
||||||
throw new FileSystemException(
|
throw FileSystemException(
|
||||||
'View "$partialName" was not found.', partialFile.path);
|
'View "$partialName" was not found.', partialFile.path);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
import 'package:file/file.dart';
|
import 'package:file/file.dart';
|
||||||
import 'package:path/path.dart' as path;
|
|
||||||
|
|
||||||
class MustacheContext {
|
class MustacheContext {
|
||||||
Directory viewDirectory;
|
Directory? viewDirectory;
|
||||||
|
|
||||||
Directory partialDirectory;
|
Directory? partialDirectory;
|
||||||
|
|
||||||
String extension;
|
String? extension;
|
||||||
|
|
||||||
MustacheContext([this.viewDirectory, this.partialDirectory, this.extension]);
|
MustacheContext([this.viewDirectory, this.partialDirectory, this.extension]);
|
||||||
|
|
||||||
File resolveView(String viewName) {
|
File resolveView(String viewName) {
|
||||||
return viewDirectory.childFile('${viewName}${extension}');
|
return viewDirectory!.childFile('$viewName$extension');
|
||||||
}
|
}
|
||||||
|
|
||||||
File resolvePartial(String partialName) {
|
File resolvePartial(String partialName) {
|
||||||
return partialDirectory.childFile('${partialName}${extension}');
|
return partialDirectory!.childFile('$partialName$extension');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
name: angel_mustache
|
name: angel_mustache
|
||||||
description: Mustache view generator for Angel.
|
|
||||||
author: thosakwe <thosakwe@gmail.com>
|
|
||||||
homepage: https://github.com/angel-dart/angel_mustache
|
|
||||||
version: 2.0.0
|
version: 2.0.0
|
||||||
|
description: Mustache view generator for Angel.
|
||||||
|
homepage: https://github.com/angel-dart/angel_mustache
|
||||||
|
publish_to: none
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.10.0 <2.12.0"
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
angel_framework: #^2.0.0-alpha
|
angel_framework: #^2.0.0-alpha
|
||||||
path: ../framework
|
git:
|
||||||
file: ^5.0.0
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
mustache4dart: ^3.0.0-dev
|
ref: sdk-2.12.x_nnbd
|
||||||
path: ^1.0.0
|
path: packages/framework
|
||||||
|
file: ^6.1.2
|
||||||
|
mustache_template: ^2.0.0
|
||||||
|
path: ^1.8.0
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
http: ^0.12.2
|
http: ^0.13.3
|
||||||
test: ^1.15.7
|
test: ^1.17.8
|
||||||
|
pedantic: ^1.11.1
|
||||||
|
|
|
@ -1,30 +1,31 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
import 'package:angel_mustache/angel_mustache.dart';
|
import 'package:angel_mustache/angel_mustache.dart';
|
||||||
|
import 'package:file/file.dart';
|
||||||
import 'package:file/local.dart';
|
import 'package:file/local.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
main() async {
|
void main() async {
|
||||||
Angel angel = new Angel();
|
var angel = Angel();
|
||||||
await angel.configure(mustache(const LocalFileSystem().directory('./test')));
|
await angel.configure(mustache(const LocalFileSystem().directory('./test')));
|
||||||
|
|
||||||
test('can render templates', () async {
|
test('can render templates', () async {
|
||||||
var hello = await angel.viewGenerator('hello', {'name': 'world'});
|
var hello = await angel.viewGenerator!('hello', {'name': 'world'});
|
||||||
var bar = await angel.viewGenerator('foo/bar', {'framework': 'angel'});
|
var bar = await angel.viewGenerator!('foo/bar', {'framework': 'angel'});
|
||||||
|
|
||||||
expect(hello, equals("Hello, world!"));
|
expect(hello, equals('Hello, world!'));
|
||||||
expect(bar, equals("angel_framework"));
|
expect(bar, equals('angel_framework'));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('throws if view is not found', () {
|
test('throws if view is not found', () {
|
||||||
expect(new Future(() async {
|
expect(Future(() async {
|
||||||
var fails = await angel.viewGenerator('fail', {'this_should': 'fail'});
|
var fails = await angel.viewGenerator!('fail', {'this_should': 'fail'});
|
||||||
print(fails);
|
print(fails);
|
||||||
}), throws);
|
}), throwsA(isA<FileSystemException>()));
|
||||||
});
|
});
|
||||||
|
|
||||||
test("partials", () async {
|
test('partials', () async {
|
||||||
var withPartial = await angel.viewGenerator('with-partial');
|
var withPartial = await angel.viewGenerator!('with-partial');
|
||||||
expect(withPartial, equals("Hello, world!"));
|
expect(withPartial, equals('Hello, world!'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
12
packages/paginate/AUTHORS.md
Normal file
12
packages/paginate/AUTHORS.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Primary Authors
|
||||||
|
===============
|
||||||
|
|
||||||
|
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
||||||
|
|
||||||
|
Thomas is the current maintainer of the code base. He has refactored and migrated the
|
||||||
|
code base to support NNBD.
|
||||||
|
|
||||||
|
* __[Tobe O](thosakwe@gmail.com)__
|
||||||
|
|
||||||
|
Tobe has written much of the original code prior to NNBD migration. He has moved on and
|
||||||
|
is no longer involved with the project.
|
|
@ -1,2 +1,5 @@
|
||||||
|
# 3.0.0
|
||||||
|
* Migrated to support Dart SDK 2.12.x NNBD
|
||||||
|
|
||||||
# 2.0.0
|
# 2.0.0
|
||||||
* Dart2 + Angel2 update.
|
* Dart2 + Angel2 update.
|
|
@ -1,4 +1,4 @@
|
||||||
MIT License (MIT)
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2021 dukefirehawk.com
|
Copyright (c) 2021 dukefirehawk.com
|
||||||
|
|
||||||
|
|
4
packages/paginate/analysis_options.yaml
Normal file
4
packages/paginate/analysis_options.yaml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
include: package:pedantic/analysis_options.yaml
|
||||||
|
analyzer:
|
||||||
|
strong-mode:
|
||||||
|
implicit-casts: false
|
|
@ -1,11 +1,11 @@
|
||||||
import 'package:angel_paginate/angel_paginate.dart';
|
import 'package:angel_paginate/angel_paginate.dart';
|
||||||
|
|
||||||
main() {
|
void main() {
|
||||||
var iterable = [1, 2, 3, 4];
|
var iterable = [1, 2, 3, 4];
|
||||||
var p = new Paginator(iterable);
|
var p = Paginator(iterable);
|
||||||
|
|
||||||
// Get the current page (default: page 1)
|
// Get the current page (default: page 1)
|
||||||
var page = p.current;
|
var page = p.current!;
|
||||||
print(page.total);
|
print(page.total);
|
||||||
print(page.startIndex);
|
print(page.startIndex);
|
||||||
print(page.data); // The actual items on this page.
|
print(page.data); // The actual items on this page.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/// Efficiently paginates collections of items in an object-oriented manner.
|
/// Efficiently paginates collections of items in an object-oriented manner.
|
||||||
class Paginator<T> {
|
class Paginator<T> {
|
||||||
final Map<int, PaginationResult<T>> _cache = {};
|
final Map<int, PaginationResult<T>> _cache = {};
|
||||||
PaginationResult<T> _current;
|
PaginationResult<T>? _current;
|
||||||
int _page = 0;
|
int _page = 0;
|
||||||
|
|
||||||
/// The collection of items to be paginated.
|
/// The collection of items to be paginated.
|
||||||
|
@ -15,7 +15,7 @@ class Paginator<T> {
|
||||||
/// For example, you would only have to paginate page 1 once. Future calls would return a cached version.
|
/// For example, you would only have to paginate page 1 once. Future calls would return a cached version.
|
||||||
final bool useCache;
|
final bool useCache;
|
||||||
|
|
||||||
Paginator(this._items, {this.itemsPerPage: 5, this.useCache: true});
|
Paginator(this._items, {this.itemsPerPage = 5, this.useCache = true});
|
||||||
|
|
||||||
/// Returns `true` if there are more items at lesser page indices than the current one.
|
/// Returns `true` if there are more items at lesser page indices than the current one.
|
||||||
bool get canGoBack => _page > 0;
|
bool get canGoBack => _page > 0;
|
||||||
|
@ -37,21 +37,23 @@ class Paginator<T> {
|
||||||
/// Fetches the current page. This will be cached until [back] or [next] is called.
|
/// Fetches the current page. This will be cached until [back] or [next] is called.
|
||||||
///
|
///
|
||||||
/// If [useCache] is `true` (default), then computations will be cached even after the page changes.
|
/// If [useCache] is `true` (default), then computations will be cached even after the page changes.
|
||||||
PaginationResult<T> get current {
|
PaginationResult<T>? get current {
|
||||||
if (_current != null)
|
if (_current != null) {
|
||||||
return _current;
|
return _current;
|
||||||
else
|
} else {
|
||||||
return _current = _getPage();
|
return _current = _getPage();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PaginationResult<T> _computePage() {
|
PaginationResult<T> _computePage() {
|
||||||
var len = _items.length;
|
var len = _items.length;
|
||||||
var it = _items.skip(_page * (itemsPerPage ?? 5));
|
//var it = _items.skip(_page * (itemsPerPage ?? 5));
|
||||||
|
var it = _items.skip(_page * (itemsPerPage));
|
||||||
var offset = len - it.length;
|
var offset = len - it.length;
|
||||||
it = it.take(itemsPerPage);
|
it = it.take(itemsPerPage);
|
||||||
var last = _lastPage();
|
var last = _lastPage();
|
||||||
// print('cur: $_page, last: $last');
|
// print('cur: $_page, last: $last');
|
||||||
return new _PaginationResultImpl(it,
|
return _PaginationResultImpl(it,
|
||||||
currentPage: _page + 1,
|
currentPage: _page + 1,
|
||||||
previousPage: _page <= 0 ? -1 : _page,
|
previousPage: _page <= 0 ? -1 : _page,
|
||||||
nextPage: _page >= last - 1 ? -1 : _page + 2,
|
nextPage: _page >= last - 1 ? -1 : _page + 2,
|
||||||
|
@ -63,11 +65,12 @@ class Paginator<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
PaginationResult<T> _getPage() {
|
PaginationResult<T> _getPage() {
|
||||||
if (useCache != false)
|
if (useCache != false) {
|
||||||
return _cache.putIfAbsent(_page, () => _computePage());
|
return _cache.putIfAbsent(_page, () => _computePage());
|
||||||
else
|
} else {
|
||||||
return _computePage();
|
return _computePage();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int _lastPage() {
|
int _lastPage() {
|
||||||
var n = (_items.length / itemsPerPage).round();
|
var n = (_items.length / itemsPerPage).round();
|
||||||
|
@ -110,40 +113,40 @@ class Paginator<T> {
|
||||||
/// Stores the result of a pagination.
|
/// Stores the result of a pagination.
|
||||||
abstract class PaginationResult<T> {
|
abstract class PaginationResult<T> {
|
||||||
factory PaginationResult.fromMap(Map<String, dynamic> map) =>
|
factory PaginationResult.fromMap(Map<String, dynamic> map) =>
|
||||||
new _PaginationResultImpl((map['data'] as Iterable).cast<T>(),
|
_PaginationResultImpl((map['data'] as List).cast<T>(),
|
||||||
currentPage: map['current_page'],
|
currentPage: map['current_page'] as int?,
|
||||||
endIndex: map['end_index'],
|
endIndex: map['end_index'] as int?,
|
||||||
itemsPerPage: map['items_per_page'],
|
itemsPerPage: map['items_per_page'] as int?,
|
||||||
nextPage: map['next_page'],
|
nextPage: map['next_page'] as int?,
|
||||||
previousPage: map['previous_page'],
|
previousPage: map['previous_page'] as int?,
|
||||||
startIndex: map['start_index'],
|
startIndex: map['start_index'] as int?,
|
||||||
total: map['total']);
|
total: map['total'] as int?);
|
||||||
|
|
||||||
List<T> get data;
|
Iterable<T> get data;
|
||||||
|
|
||||||
int get currentPage;
|
int? get currentPage;
|
||||||
|
|
||||||
int get previousPage;
|
int? get previousPage;
|
||||||
|
|
||||||
int get nextPage;
|
int? get nextPage;
|
||||||
|
|
||||||
int get itemsPerPage;
|
int? get itemsPerPage;
|
||||||
|
|
||||||
int get total;
|
int? get total;
|
||||||
|
|
||||||
int get startIndex;
|
int? get startIndex;
|
||||||
|
|
||||||
int get endIndex;
|
int? get endIndex;
|
||||||
|
|
||||||
Map<String, dynamic> toJson();
|
Map<String, dynamic> toJson();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PaginationResultImpl<T> implements PaginationResult<T> {
|
class _PaginationResultImpl<T> implements PaginationResult<T> {
|
||||||
final Iterable<T> _data;
|
final Iterable<T> _data;
|
||||||
Iterable<T> _cachedData;
|
Iterable<T>? _cachedData;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final int currentPage;
|
final int? currentPage;
|
||||||
|
|
||||||
_PaginationResultImpl(this._data,
|
_PaginationResultImpl(this._data,
|
||||||
{this.currentPage,
|
{this.currentPage,
|
||||||
|
@ -155,25 +158,25 @@ class _PaginationResultImpl<T> implements PaginationResult<T> {
|
||||||
this.total});
|
this.total});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<T> get data => _cachedData ?? (_cachedData = new List<T>.from(_data));
|
Iterable<T> get data => _cachedData ?? (_cachedData = List<T>.from(_data));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final int endIndex;
|
final int? endIndex;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final int itemsPerPage;
|
final int? itemsPerPage;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final int nextPage;
|
final int? nextPage;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final int previousPage;
|
final int? previousPage;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final int startIndex;
|
final int? startIndex;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final int total;
|
final int? total;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
|
|
|
@ -1,15 +1,22 @@
|
||||||
name: angel_paginate
|
name: angel_paginate
|
||||||
version: 2.0.0
|
version: 3.0.0
|
||||||
description: Platform-agnostic pagination library, with custom support for the Angel framework.
|
description: Platform-agnostic pagination library, with custom support for the Angel framework.
|
||||||
author: Tobe O <thosakwe@gmail.com>
|
|
||||||
homepage: https://github.com/angel-dart/paginate
|
homepage: https://github.com/angel-dart/paginate
|
||||||
|
publish_to: none
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.10.0 <2.12.0"
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
angel_framework: #^2.0.0-alpha
|
angel_framework:
|
||||||
path: ../framework
|
git:
|
||||||
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
|
ref: sdk-2.12.x_nnbd
|
||||||
|
path: packages/framework
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
angel_test: #^2.0.0
|
angel_test:
|
||||||
path: ../test
|
git:
|
||||||
logging: ^0.11.0
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
test: ^1.15.7
|
ref: sdk-2.12.x_nnbd
|
||||||
|
path: packages/test
|
||||||
|
logging: ^1.0.1
|
||||||
|
test: ^1.17.8
|
||||||
|
pedantic: ^1.11.1
|
|
@ -2,7 +2,7 @@ import 'package:test/test.dart';
|
||||||
import 'bounds_test.dart' as bounds;
|
import 'bounds_test.dart' as bounds;
|
||||||
import 'paginate_test.dart' as paginate;
|
import 'paginate_test.dart' as paginate;
|
||||||
|
|
||||||
main() {
|
void main() {
|
||||||
group('bounds', bounds.main);
|
group('bounds', bounds.main);
|
||||||
group('paginate', paginate.main);
|
group('paginate', paginate.main);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,15 +11,15 @@ final List<Map<String, String>> mjAlbums = [
|
||||||
{'michael': 'jackson'}
|
{'michael': 'jackson'}
|
||||||
];
|
];
|
||||||
|
|
||||||
main() {
|
void main() {
|
||||||
TestClient client;
|
late TestClient client;
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
var app = Angel();
|
var app = Angel();
|
||||||
|
|
||||||
app.get('/api/songs', (req, res) {
|
app.get('/api/songs', (req, res) {
|
||||||
var p = Paginator(mjAlbums, itemsPerPage: mjAlbums.length);
|
var p = Paginator(mjAlbums, itemsPerPage: mjAlbums.length);
|
||||||
p.goToPage(int.parse(req.queryParameters['page'] ?? '1'));
|
p.goToPage(int.parse(req.queryParameters['page'] as String? ?? '1'));
|
||||||
return p.current;
|
return p.current;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ main() {
|
||||||
queryParameters: {r'$limit': (mjAlbums.length + 1).toString()}));
|
queryParameters: {r'$limit': (mjAlbums.length + 1).toString()}));
|
||||||
|
|
||||||
var page = PaginationResult<Map<String, dynamic>>.fromMap(
|
var page = PaginationResult<Map<String, dynamic>>.fromMap(
|
||||||
json.decode(response.body));
|
json.decode(response.body) as Map<String, dynamic>);
|
||||||
|
|
||||||
print('page: ${page.toJson()}');
|
print('page: ${page.toJson()}');
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ void main() {
|
||||||
test('first page', () {
|
test('first page', () {
|
||||||
var paginator = Paginator<int>(DATA);
|
var paginator = Paginator<int>(DATA);
|
||||||
expect(paginator.pageNumber, 1);
|
expect(paginator.pageNumber, 1);
|
||||||
var r = paginator.current;
|
var r = paginator.current!;
|
||||||
print(r.toJson());
|
print(r.toJson());
|
||||||
expect(r.total, DATA.length);
|
expect(r.total, DATA.length);
|
||||||
expect(r.itemsPerPage, 5);
|
expect(r.itemsPerPage, 5);
|
||||||
|
@ -62,14 +62,14 @@ void main() {
|
||||||
expect(r.nextPage, 2);
|
expect(r.nextPage, 2);
|
||||||
expect(r.startIndex, 0);
|
expect(r.startIndex, 0);
|
||||||
expect(r.endIndex, 4);
|
expect(r.endIndex, 4);
|
||||||
expect(r.data, DATA.skip(r.startIndex).take(r.itemsPerPage).toList());
|
expect(r.data, DATA.skip(r.startIndex!).take(r.itemsPerPage!).toList());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('third page', () {
|
test('third page', () {
|
||||||
var paginator = Paginator<int>(DATA)..goToPage(3);
|
var paginator = Paginator<int>(DATA)..goToPage(3);
|
||||||
expect(paginator.pageNumber, 3);
|
expect(paginator.pageNumber, 3);
|
||||||
var r = paginator.current;
|
var r = paginator.current!;
|
||||||
print(r.toJson());
|
print(r.toJson());
|
||||||
expect(r.total, DATA.length);
|
expect(r.total, DATA.length);
|
||||||
expect(r.itemsPerPage, 5);
|
expect(r.itemsPerPage, 5);
|
||||||
|
@ -78,7 +78,7 @@ void main() {
|
||||||
expect(r.nextPage, 4);
|
expect(r.nextPage, 4);
|
||||||
expect(r.startIndex, 10);
|
expect(r.startIndex, 10);
|
||||||
expect(r.endIndex, 14);
|
expect(r.endIndex, 14);
|
||||||
expect(r.data, DATA.skip(r.startIndex).take(r.itemsPerPage).toList());
|
expect(r.data, DATA.skip(r.startIndex!).take(r.itemsPerPage!).toList());
|
||||||
|
|
||||||
paginator.back();
|
paginator.back();
|
||||||
expect(paginator.pageNumber, 2);
|
expect(paginator.pageNumber, 2);
|
||||||
|
@ -87,7 +87,7 @@ void main() {
|
||||||
test('last page', () {
|
test('last page', () {
|
||||||
var paginator = Paginator<int>(DATA);
|
var paginator = Paginator<int>(DATA);
|
||||||
paginator.goToPage(paginator.lastPageNumber);
|
paginator.goToPage(paginator.lastPageNumber);
|
||||||
var r = paginator.current;
|
var r = paginator.current!;
|
||||||
expect(r.total, DATA.length);
|
expect(r.total, DATA.length);
|
||||||
expect(r.itemsPerPage, 5);
|
expect(r.itemsPerPage, 5);
|
||||||
expect(r.previousPage, paginator.lastPageNumber - 1);
|
expect(r.previousPage, paginator.lastPageNumber - 1);
|
||||||
|
@ -96,7 +96,7 @@ void main() {
|
||||||
expect(r.startIndex, (paginator.lastPageNumber - 1) * 5);
|
expect(r.startIndex, (paginator.lastPageNumber - 1) * 5);
|
||||||
expect(r.endIndex, r.startIndex);
|
expect(r.endIndex, r.startIndex);
|
||||||
expect(r.data, [DATA.last]);
|
expect(r.data, [DATA.last]);
|
||||||
expect(r.data, DATA.skip(r.startIndex).take(r.itemsPerPage).toList());
|
expect(r.data, DATA.skip(r.startIndex!).take(r.itemsPerPage!).toList());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('dump pages', () {
|
test('dump pages', () {
|
||||||
|
@ -104,14 +104,14 @@ void main() {
|
||||||
print('${paginator.lastPageNumber} page(s) of data:');
|
print('${paginator.lastPageNumber} page(s) of data:');
|
||||||
|
|
||||||
do {
|
do {
|
||||||
print(' * Page #${paginator.pageNumber}: ${paginator.current.data}');
|
print(' * Page #${paginator.pageNumber}: ${paginator.current!.data}');
|
||||||
paginator.next();
|
paginator.next();
|
||||||
} while (paginator.canGoForward);
|
} while (paginator.canGoForward);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('empty collection', () {
|
test('empty collection', () {
|
||||||
var paginator = Paginator([]);
|
var paginator = Paginator([]);
|
||||||
var page = paginator.current;
|
var page = paginator.current!;
|
||||||
print(page.toJson());
|
print(page.toJson());
|
||||||
|
|
||||||
expect(page.total, 0);
|
expect(page.total, 0);
|
||||||
|
|
12
packages/poll/AUTHORS.md
Normal file
12
packages/poll/AUTHORS.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Primary Authors
|
||||||
|
===============
|
||||||
|
|
||||||
|
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
||||||
|
|
||||||
|
Thomas is the current maintainer of the code base. He has refactored and migrated the
|
||||||
|
code base to support NNBD.
|
||||||
|
|
||||||
|
* __[Tobe O](thosakwe@gmail.com)__
|
||||||
|
|
||||||
|
Tobe has written much of the original code prior to NNBD migration. He has moved on and
|
||||||
|
is no longer involved with the project.
|
|
@ -1,2 +1,5 @@
|
||||||
|
# 2.0.0
|
||||||
|
* Migrated to support Dart SDK 2.12.x NNBD
|
||||||
|
|
||||||
# 1.0.0
|
# 1.0.0
|
||||||
* Created package + tests
|
* Created package + tests
|
|
@ -1,4 +1,4 @@
|
||||||
MIT License (MIT)
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2021 dukefirehawk.com
|
Copyright (c) 2021 dukefirehawk.com
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
|
include: package:pedantic/analysis_options.yaml
|
||||||
analyzer:
|
analyzer:
|
||||||
strong-mode: true
|
strong-mode:
|
||||||
|
implicit-casts: false
|
|
@ -1,11 +1,11 @@
|
||||||
import 'package:angel_client/io.dart';
|
import 'package:angel_client/io.dart';
|
||||||
import 'package:angel_poll/angel_poll.dart';
|
import 'package:angel_poll/angel_poll.dart';
|
||||||
|
|
||||||
main() {
|
void main() {
|
||||||
var app = new Rest('http://localhost:3000');
|
var app = Rest('http://localhost:3000');
|
||||||
|
|
||||||
var todos = new ServiceList(
|
var todos = ServiceList(
|
||||||
new PollingService(
|
PollingService(
|
||||||
// Typically, you'll pass a REST-based service instance here.
|
// Typically, you'll pass a REST-based service instance here.
|
||||||
app.service('api/todos'),
|
app.service('api/todos'),
|
||||||
|
|
||||||
|
|
|
@ -41,21 +41,20 @@ class PollingService extends Service {
|
||||||
final List _items = [];
|
final List _items = [];
|
||||||
final List<StreamSubscription> _subs = [];
|
final List<StreamSubscription> _subs = [];
|
||||||
|
|
||||||
final StreamController _onIndexed = new StreamController(),
|
final StreamController<List<dynamic>> _onIndexed = StreamController(),
|
||||||
_onRead = new StreamController(),
|
_onRead = StreamController(),
|
||||||
_onCreated = new StreamController(),
|
_onCreated = StreamController(),
|
||||||
_onModified = new StreamController(),
|
_onModified = StreamController(),
|
||||||
_onUpdated = new StreamController(),
|
_onUpdated = StreamController(),
|
||||||
_onRemoved = new StreamController();
|
_onRemoved = StreamController();
|
||||||
|
|
||||||
Timer _timer;
|
late Timer _timer;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Angel get app => inner.app;
|
Angel get app => inner.app;
|
||||||
|
|
||||||
// TODO: To revisit this logic
|
|
||||||
@override
|
@override
|
||||||
Stream<List> get onIndexed => _onIndexed.stream;
|
Stream<List<dynamic>> get onIndexed => _onIndexed.stream;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream get onRead => _onRead.stream;
|
Stream get onRead => _onRead.stream;
|
||||||
|
@ -73,16 +72,18 @@ class PollingService extends Service {
|
||||||
Stream get onRemoved => _onRemoved.stream;
|
Stream get onRemoved => _onRemoved.stream;
|
||||||
|
|
||||||
PollingService(this.inner, Duration interval,
|
PollingService(this.inner, Duration interval,
|
||||||
{this.checkForCreated: true,
|
{this.checkForCreated = true,
|
||||||
this.checkForModified: true,
|
this.checkForModified = true,
|
||||||
this.checkForRemoved: true,
|
this.checkForRemoved = true,
|
||||||
this.idField: 'id',
|
this.idField = 'id',
|
||||||
this.asPaginated: false,
|
this.asPaginated = false,
|
||||||
EqualityBy compareId,
|
EqualityBy? compareId,
|
||||||
this.compareItems: const MapEquality()})
|
this.compareItems = const MapEquality()})
|
||||||
: compareId = compareId ?? new EqualityBy((map) => map[idField ?? 'id']) {
|
: compareId = compareId ?? EqualityBy((map) => map[idField]) {
|
||||||
_timer = new Timer.periodic(interval, (_) {
|
_timer = Timer.periodic(interval, (_) {
|
||||||
index().catchError(_onIndexed.addError);
|
index().catchError((error) {
|
||||||
|
_onIndexed.addError(error as Object);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var streams = <Stream, StreamController>{
|
var streams = <Stream, StreamController>{
|
||||||
|
@ -109,20 +110,21 @@ class PollingService extends Service {
|
||||||
Future close() async {
|
Future close() async {
|
||||||
_timer.cancel();
|
_timer.cancel();
|
||||||
_subs.forEach((s) => s.cancel());
|
_subs.forEach((s) => s.cancel());
|
||||||
_onIndexed.close();
|
await _onIndexed.close();
|
||||||
_onRead.close();
|
await _onRead.close();
|
||||||
_onCreated.close();
|
await _onCreated.close();
|
||||||
_onModified.close();
|
await _onModified.close();
|
||||||
_onUpdated.close();
|
await _onUpdated.close();
|
||||||
_onRemoved.close();
|
await _onRemoved.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: To revisit this logic
|
// TODO: To revisit this logic
|
||||||
@override
|
@override
|
||||||
Future<List> index([Map params]) {
|
Future<List<dynamic>> index([Map? params]) {
|
||||||
return inner.index().then((data) {
|
return inner.index().then((data) {
|
||||||
//return asPaginated == true ? data['data'] : data;
|
//return asPaginated == true ? data['data'] : data;
|
||||||
return asPaginated == true ? data[0] : data;
|
//return asPaginated == true ? data[0] : data;
|
||||||
|
return data!;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,17 +134,17 @@ class PollingService extends Service {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@override
|
@override
|
||||||
Future remove(id, [Map params]) {
|
Future remove(id, [Map<String, dynamic>? params]) {
|
||||||
return inner.remove(id, params).then((result) {
|
return inner.remove(id, params).then((result) {
|
||||||
_items.remove(result);
|
_items.remove(result);
|
||||||
return result;
|
return result;
|
||||||
}).catchError(_onRemoved.addError);
|
}).catchError(_onRemoved.addError);
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleUpdate(result) {
|
dynamic _handleUpdate(result) {
|
||||||
int index = -1;
|
var index = -1;
|
||||||
|
|
||||||
for (int i = 0; i < _items.length; i++) {
|
for (var i = 0; i < _items.length; i++) {
|
||||||
if (compareId.equals(_items[i], result)) {
|
if (compareId.equals(_items[i], result)) {
|
||||||
index = i;
|
index = i;
|
||||||
break;
|
break;
|
||||||
|
@ -157,7 +159,7 @@ class PollingService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future update(id, data, [Map params]) {
|
Future update(id, data, [Map<String, dynamic>? params]) {
|
||||||
return inner
|
return inner
|
||||||
.update(id, data, params)
|
.update(id, data, params)
|
||||||
.then(_handleUpdate)
|
.then(_handleUpdate)
|
||||||
|
@ -165,7 +167,7 @@ class PollingService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future modify(id, data, [Map params]) {
|
Future modify(id, data, [Map<String, dynamic>? params]) {
|
||||||
return inner
|
return inner
|
||||||
.modify(id, data, params)
|
.modify(id, data, params)
|
||||||
.then(_handleUpdate)
|
.then(_handleUpdate)
|
||||||
|
@ -173,7 +175,7 @@ class PollingService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future create(data, [Map params]) {
|
Future create(data, [Map<String, dynamic>? params]) {
|
||||||
return inner.create(data, params).then((result) {
|
return inner.create(data, params).then((result) {
|
||||||
_items.add(result);
|
_items.add(result);
|
||||||
return result;
|
return result;
|
||||||
|
@ -181,18 +183,19 @@ class PollingService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future read(id, [Map params]) {
|
Future read(id, [Map<String, dynamic>? params]) {
|
||||||
return inner.read(id, params);
|
return inner.read(id, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleIndexed(data) {
|
void _handleIndexed(List<dynamic> data) {
|
||||||
var items = asPaginated == true ? data['data'] : data;
|
//var items = asPaginated == true ? data['data'] : data;
|
||||||
bool changesComputed = false;
|
var items = data;
|
||||||
|
var changesComputed = false;
|
||||||
|
|
||||||
if (checkForCreated != false) {
|
if (checkForCreated != false) {
|
||||||
var newItems = <int, dynamic>{};
|
var newItems = <int, dynamic>{};
|
||||||
|
|
||||||
for (int i = 0; i < items.length; i++) {
|
for (var i = 0; i < items.length; i++) {
|
||||||
var item = items[i];
|
var item = items[i];
|
||||||
|
|
||||||
if (!_items.any((i) => compareId.equals(i, item))) {
|
if (!_items.any((i) => compareId.equals(i, item))) {
|
||||||
|
@ -202,7 +205,7 @@ class PollingService extends Service {
|
||||||
|
|
||||||
newItems.forEach((index, item) {
|
newItems.forEach((index, item) {
|
||||||
_items.insert(index, item);
|
_items.insert(index, item);
|
||||||
_onCreated.add(item);
|
_onCreated.add([item]);
|
||||||
});
|
});
|
||||||
|
|
||||||
changesComputed = newItems.isNotEmpty;
|
changesComputed = newItems.isNotEmpty;
|
||||||
|
@ -211,7 +214,7 @@ class PollingService extends Service {
|
||||||
if (checkForRemoved != false) {
|
if (checkForRemoved != false) {
|
||||||
var removedItems = <int, dynamic>{};
|
var removedItems = <int, dynamic>{};
|
||||||
|
|
||||||
for (int i = 0; i < _items.length; i++) {
|
for (var i = 0; i < _items.length; i++) {
|
||||||
var item = _items[i];
|
var item = _items[i];
|
||||||
|
|
||||||
if (!items.any((i) => compareId.equals(i, item))) {
|
if (!items.any((i) => compareId.equals(i, item))) {
|
||||||
|
@ -221,7 +224,7 @@ class PollingService extends Service {
|
||||||
|
|
||||||
removedItems.forEach((index, item) {
|
removedItems.forEach((index, item) {
|
||||||
_items.removeAt(index);
|
_items.removeAt(index);
|
||||||
_onRemoved.add(item);
|
_onRemoved.add([item]);
|
||||||
});
|
});
|
||||||
|
|
||||||
changesComputed = changesComputed || removedItems.isNotEmpty;
|
changesComputed = changesComputed || removedItems.isNotEmpty;
|
||||||
|
@ -231,7 +234,7 @@ class PollingService extends Service {
|
||||||
var modifiedItems = <int, dynamic>{};
|
var modifiedItems = <int, dynamic>{};
|
||||||
|
|
||||||
for (var item in items) {
|
for (var item in items) {
|
||||||
for (int i = 0; i < _items.length; i++) {
|
for (var i = 0; i < _items.length; i++) {
|
||||||
var localItem = _items[i];
|
var localItem = _items[i];
|
||||||
|
|
||||||
if (compareId.equals(item, localItem)) {
|
if (compareId.equals(item, localItem)) {
|
||||||
|
@ -244,7 +247,7 @@ class PollingService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
modifiedItems.forEach((index, item) {
|
modifiedItems.forEach((index, item) {
|
||||||
_onModified.add(_items[index] = item);
|
_onModified.add([_items[index] = item]);
|
||||||
});
|
});
|
||||||
|
|
||||||
changesComputed = changesComputed || modifiedItems.isNotEmpty;
|
changesComputed = changesComputed || modifiedItems.isNotEmpty;
|
||||||
|
@ -253,8 +256,8 @@ class PollingService extends Service {
|
||||||
if (!changesComputed) {
|
if (!changesComputed) {
|
||||||
_items
|
_items
|
||||||
..clear()
|
..clear()
|
||||||
..addAll(items);
|
..add(items);
|
||||||
_onIndexed.add(items);
|
_onIndexed.add([items]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,23 @@
|
||||||
name: angel_poll
|
name: angel_poll
|
||||||
version: 1.0.0
|
version: 2.0.0
|
||||||
description: package:angel_client support for "realtime" interactions with Angel via long polling.
|
description: package:angel_client support for "realtime" interactions with Angel via long polling.
|
||||||
author: Tobe O <thosakwe@gmail.com>
|
publish_to: none
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.7.0 <3.0.0"
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
homepage: https://github.com/angel-dart/poll
|
homepage: https://github.com/angel-dart/poll
|
||||||
dependencies:
|
dependencies:
|
||||||
angel_client: # ^1.0.0
|
angel_client: # ^1.0.0
|
||||||
path: ../client
|
git:
|
||||||
async: ">=1.10.0 <3.0.0"
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
collection: ^1.14.12
|
ref: sdk-2.12.x_nnbd
|
||||||
|
path: packages/client
|
||||||
|
async: ^2.7.0
|
||||||
|
collection: ^1.15.0
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
angel_test: # ^1.1.0
|
angel_test:
|
||||||
path: ../test
|
git:
|
||||||
test: ^1.15.7
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
|
ref: sdk-2.12.x_nnbd
|
||||||
|
path: packages/test
|
||||||
|
test: ^1.17.8
|
||||||
|
pedantic: ^1.11.1
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:angel_framework/angel_framework.dart' as srv;
|
import 'package:angel_framework/angel_framework.dart' as srv;
|
||||||
|
import 'package:angel_container/mirrors.dart';
|
||||||
import 'package:angel_poll/angel_poll.dart';
|
import 'package:angel_poll/angel_poll.dart';
|
||||||
import 'package:angel_test/angel_test.dart';
|
import 'package:angel_test/angel_test.dart';
|
||||||
import 'package:async/async.dart';
|
import 'package:async/async.dart';
|
||||||
|
@ -6,13 +7,18 @@ import 'package:logging/logging.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
srv.Service store;
|
late srv.Service store;
|
||||||
TestClient client;
|
late TestClient client;
|
||||||
PollingService pollingService;
|
late PollingService pollingService;
|
||||||
|
|
||||||
|
var created;
|
||||||
|
late StreamQueue onCreated;
|
||||||
|
late StreamQueue onModified;
|
||||||
|
late StreamQueue onRemoved;
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
var app = new srv.Angel();
|
var app = srv.Angel(reflector: MirrorsReflector());
|
||||||
app.logger = new Logger.detached('angel_poll')
|
app.logger = Logger.detached('angel_poll')
|
||||||
..onRecord.listen((rec) {
|
..onRecord.listen((rec) {
|
||||||
print(rec);
|
print(rec);
|
||||||
if (rec.error != null) {
|
if (rec.error != null) {
|
||||||
|
@ -23,29 +29,21 @@ void main() {
|
||||||
|
|
||||||
store = app.use(
|
store = app.use(
|
||||||
'/api/todos',
|
'/api/todos',
|
||||||
new srv.MapService(
|
srv.MapService(
|
||||||
autoIdAndDateFields: false,
|
autoIdAndDateFields: false,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
client = await connectTo(app);
|
client = await connectTo(app);
|
||||||
|
|
||||||
pollingService = new PollingService(
|
pollingService = PollingService(
|
||||||
client.service('api/todos'),
|
client.service('api/todos'),
|
||||||
const Duration(milliseconds: 100),
|
const Duration(milliseconds: 100),
|
||||||
);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() => client.close());
|
onCreated = StreamQueue(pollingService.onCreated);
|
||||||
|
onModified = StreamQueue(pollingService.onModified);
|
||||||
group('events', () {
|
onRemoved = StreamQueue(pollingService.onRemoved);
|
||||||
var created;
|
|
||||||
StreamQueue onCreated, onModified, onRemoved;
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
onCreated = new StreamQueue(pollingService.onCreated);
|
|
||||||
onModified = new StreamQueue(pollingService.onModified);
|
|
||||||
onRemoved = new StreamQueue(pollingService.onRemoved);
|
|
||||||
|
|
||||||
created = await store.create({
|
created = await store.create({
|
||||||
'id': '0',
|
'id': '0',
|
||||||
|
@ -58,8 +56,10 @@ void main() {
|
||||||
onCreated.cancel();
|
onCreated.cancel();
|
||||||
onModified.cancel();
|
onModified.cancel();
|
||||||
onRemoved.cancel();
|
onRemoved.cancel();
|
||||||
|
client.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group('events', () {
|
||||||
test('fires indexed', () async {
|
test('fires indexed', () async {
|
||||||
var indexed = await pollingService.index();
|
var indexed = await pollingService.index();
|
||||||
print(indexed);
|
print(indexed);
|
||||||
|
@ -80,7 +80,7 @@ void main() {
|
||||||
|
|
||||||
var result = await onModified.next;
|
var result = await onModified.next;
|
||||||
print(result);
|
print(result);
|
||||||
expect(result, new Map.from(created)..['text'] = 'go to school');
|
expect(result, Map.from({'': created})..['text'] = 'go to school');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('manual modify', () async {
|
test('manual modify', () async {
|
||||||
|
@ -91,7 +91,7 @@ void main() {
|
||||||
|
|
||||||
var result = await onModified.next;
|
var result = await onModified.next;
|
||||||
print(result);
|
print(result);
|
||||||
expect(result, new Map.from(created)..['text'] = 'eat');
|
expect(result, Map.from({'': created})..['text'] = 'eat');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('fires removed', () async {
|
test('fires removed', () async {
|
||||||
|
|
12
packages/redis/AUTHORS.md
Normal file
12
packages/redis/AUTHORS.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Primary Authors
|
||||||
|
===============
|
||||||
|
|
||||||
|
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
||||||
|
|
||||||
|
Thomas is the current maintainer of the code base. He has refactored and migrated the
|
||||||
|
code base to support NNBD.
|
||||||
|
|
||||||
|
* __[Tobe O](thosakwe@gmail.com)__
|
||||||
|
|
||||||
|
Tobe has written much of the original code prior to NNBD migration. He has moved on and
|
||||||
|
is no longer involved with the project.
|
|
@ -1,2 +1,5 @@
|
||||||
|
# 2.0.0
|
||||||
|
* Migrated to support Dart SDK 2.12.x NNBD
|
||||||
|
|
||||||
# 1.0.0
|
# 1.0.0
|
||||||
* First version.
|
* First version.
|
|
@ -1,6 +1,6 @@
|
||||||
MIT License (MIT)
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2021 dukefirehawk.com
|
Copyright (c) 2018 The Angel Framework
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
4
packages/redis/analysis_options.yaml
Normal file
4
packages/redis/analysis_options.yaml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
include: package:pedantic/analysis_options.yaml
|
||||||
|
analyzer:
|
||||||
|
strong-mode:
|
||||||
|
implicit-casts: false
|
|
@ -1,17 +1,18 @@
|
||||||
import 'package:angel_redis/angel_redis.dart';
|
import 'package:angel_redis/angel_redis.dart';
|
||||||
import 'package:resp_client/resp_client.dart';
|
import 'package:resp_client/resp_client.dart';
|
||||||
import 'package:resp_client/resp_commands.dart';
|
import 'package:resp_client/resp_commands.dart';
|
||||||
|
import 'package:resp_client/resp_server.dart';
|
||||||
|
|
||||||
main() async {
|
void main() async {
|
||||||
var connection = await connectSocket('localhost');
|
var connection = await connectSocket('localhost');
|
||||||
var client = new RespClient(connection);
|
var client = RespClient(connection);
|
||||||
var service = new RedisService(new RespCommands(client), prefix: 'example');
|
var service = RedisService(RespCommandsTier2(client), prefix: 'example');
|
||||||
|
|
||||||
// Create an object
|
// Create an object
|
||||||
await service.create({'id': 'a', 'hello': 'world'});
|
await service.create({'id': 'a', 'hello': 'world'});
|
||||||
|
|
||||||
// Read it...
|
// Read it...
|
||||||
var read = await service.read('a');
|
var read = await (service.read('a'));
|
||||||
print(read['hello']);
|
print(read['hello']);
|
||||||
|
|
||||||
// Delete it.
|
// Delete it.
|
||||||
|
|
|
@ -6,92 +6,99 @@ import 'package:resp_client/resp_commands.dart';
|
||||||
|
|
||||||
/// An Angel service that reads and writes JSON within a Redis store.
|
/// An Angel service that reads and writes JSON within a Redis store.
|
||||||
class RedisService extends Service<String, Map<String, dynamic>> {
|
class RedisService extends Service<String, Map<String, dynamic>> {
|
||||||
final RespCommands respCommands;
|
final RespCommandsTier2 respCommands;
|
||||||
|
|
||||||
/// An optional string prefixed to keys before they are inserted into Redis.
|
/// An optional string prefixed to keys before they are inserted into Redis.
|
||||||
///
|
///
|
||||||
/// Consider using this if you are using several different Redis collections
|
/// Consider using this if you are using several different Redis collections
|
||||||
/// within a single application.
|
/// within a single application.
|
||||||
final String prefix;
|
final String? prefix;
|
||||||
|
|
||||||
RedisService(this.respCommands, {this.prefix});
|
RedisService(this.respCommands, {this.prefix});
|
||||||
|
|
||||||
String _applyPrefix(String id) => prefix == null ? id : '$prefix:$id';
|
String? _applyPrefix(String? id) => prefix == null ? id : '$prefix:$id';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<Map<String, dynamic>>> index(
|
Future<List<Map<String, dynamic>>> index(
|
||||||
[Map<String, dynamic> params]) async {
|
[Map<String, dynamic>? params]) async {
|
||||||
var result =
|
var result =
|
||||||
await respCommands.client.writeArrayOfBulk(['KEYS', _applyPrefix('*')]);
|
//await respCommands.client.writeArrayOfBulk(['KEYS', _applyPrefix('*')]);
|
||||||
|
await respCommands.tier1.tier0.execute(['KEYS', _applyPrefix('*')]);
|
||||||
var keys = result.payload.map((RespType s) => s.payload) as Iterable;
|
var keys = result.payload.map((RespType s) => s.payload) as Iterable;
|
||||||
if (keys.isEmpty) return [];
|
if (keys.isEmpty) return [];
|
||||||
result = await respCommands.client.writeArrayOfBulk(['MGET']..addAll(keys));
|
//result = await respCommands.client.writeArrayOfBulk(['MGET']..addAll(keys));
|
||||||
return result.payload
|
result = await respCommands.tier1.tier0.execute(['MGET', ...keys]);
|
||||||
.map<Map<String, dynamic>>(
|
|
||||||
(RespType s) => json.decode(s.payload) as Map<String, dynamic>)
|
if (result.isArray) {
|
||||||
|
return (result as List<RespType>)
|
||||||
|
.map<Map<String, dynamic>>((RespType s) =>
|
||||||
|
json.decode(s.payload as String) as Map<String, dynamic>)
|
||||||
.toList();
|
.toList();
|
||||||
|
} else {
|
||||||
|
// TODO: To be reviewed for handling none array objects
|
||||||
|
return [json.decode(result.payload as String) as Map<String, dynamic>];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Map<String, dynamic>> read(String id,
|
Future<Map<String, dynamic>> read(String id,
|
||||||
[Map<String, dynamic> params]) async {
|
[Map<String, dynamic>? params]) async {
|
||||||
var value = await respCommands.get(_applyPrefix(id));
|
var value = await respCommands.get(_applyPrefix(id)!);
|
||||||
|
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
throw new AngelHttpException.notFound(
|
throw AngelHttpException.notFound(message: 'No record found for ID $id');
|
||||||
message: 'No record found for ID $id');
|
|
||||||
} else {
|
} else {
|
||||||
return json.decode(value);
|
return json.decode(value) as Map<String, dynamic>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Map<String, dynamic>> create(Map<String, dynamic> data,
|
Future<Map<String, dynamic>> create(Map<String, dynamic>? data,
|
||||||
[Map<String, dynamic> params]) async {
|
[Map<String, dynamic>? params]) async {
|
||||||
String id;
|
String? id;
|
||||||
if (data['id'] != null)
|
if (data!['id'] != null) {
|
||||||
id = data['id'] as String;
|
id = data['id'] as String?;
|
||||||
else {
|
} else {
|
||||||
var keyVar = await respCommands.client
|
var keyVar = await respCommands.tier1.tier0
|
||||||
.writeArrayOfBulk(['INCR', _applyPrefix('angel_redis:id')]);
|
.execute(['INCR', _applyPrefix('angel_redis:id')]);
|
||||||
id = keyVar.payload.toString();
|
id = keyVar.payload.toString();
|
||||||
data = new Map<String, dynamic>.from(data)..['id'] = id;
|
data = Map<String, dynamic>.from(data)..['id'] = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
await respCommands.set(_applyPrefix(id), json.encode(data));
|
await respCommands.set(_applyPrefix(id)!, json.encode(data));
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Map<String, dynamic>> modify(String id, Map<String, dynamic> data,
|
Future<Map<String, dynamic>> modify(String id, Map<String, dynamic>? data,
|
||||||
[Map<String, dynamic> params]) async {
|
[Map<String, dynamic>? params]) async {
|
||||||
var input = await read(id);
|
var input = await (read(id));
|
||||||
input.addAll(data);
|
input.addAll(data!);
|
||||||
return await update(id, input, params);
|
return await update(id, input, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Map<String, dynamic>> update(String id, Map<String, dynamic> data,
|
Future<Map<String, dynamic>> update(String id, Map<String, dynamic>? data,
|
||||||
[Map<String, dynamic> params]) async {
|
[Map<String, dynamic>? params]) async {
|
||||||
data = new Map<String, dynamic>.from(data)..['id'] = id;
|
data = Map<String, dynamic>.from(data!)..['id'] = id;
|
||||||
await respCommands.set(_applyPrefix(id), json.encode(data));
|
await respCommands.set(_applyPrefix(id)!, json.encode(data));
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Map<String, dynamic>> remove(String id,
|
Future<Map<String, dynamic>> remove(String id,
|
||||||
[Map<String, dynamic> params]) async {
|
[Map<String, dynamic>? params]) async {
|
||||||
var client = respCommands.client;
|
var client = respCommands.tier1.tier0;
|
||||||
await client.writeArrayOfBulk(['MULTI']);
|
await client.execute(['MULTI']);
|
||||||
await client.writeArrayOfBulk(['GET', _applyPrefix(id)]);
|
await client.execute(['GET', _applyPrefix(id)]);
|
||||||
await client.writeArrayOfBulk(['DEL', _applyPrefix(id)]);
|
await client.execute(['DEL', _applyPrefix(id)]);
|
||||||
var result = await client.writeArrayOfBulk(['EXEC']);
|
var result = await client.execute(['EXEC']);
|
||||||
var str = result.payload[0] as RespBulkString;
|
var str = result.payload[0] as RespBulkString;
|
||||||
|
|
||||||
if (str.payload == null)
|
if (str.payload == null) {
|
||||||
throw new AngelHttpException.notFound(
|
throw AngelHttpException.notFound(message: 'No record found for ID $id');
|
||||||
message: 'No record found for ID $id');
|
} else {
|
||||||
else
|
return json.decode(str.payload!) as Map<String, dynamic>;
|
||||||
return json.decode(str.payload);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,22 @@
|
||||||
name: angel_redis
|
name: angel_redis
|
||||||
version: 1.0.0
|
version: 2.0.0
|
||||||
description: An Angel service provider for Redis. Works well for caching volatile data.
|
description: An Angel service provider for Redis. Works well for caching volatile data.
|
||||||
author: Tobe O <thosakwe@gmail.com>
|
|
||||||
homepage: https://github.com/angel-dart/redis
|
homepage: https://github.com/angel-dart/redis
|
||||||
|
publish_to: none
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.10.0 <2.12.0"
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
angel_framework: #^2.0.0-alpha
|
angel_framework:
|
||||||
path: ../framework
|
git:
|
||||||
angel_http_exception: #^1.0.0
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
path: ../http_exception
|
ref: sdk-2.12.x_nnbd
|
||||||
resp_client: ^0.1.6
|
path: packages/framework
|
||||||
|
angel_http_exception:
|
||||||
|
git:
|
||||||
|
url: https://github.com/dukefirehawk/angel.git
|
||||||
|
ref: sdk-2.12.x_nnbd
|
||||||
|
path: packages/http_exception
|
||||||
|
resp_client: ^1.2.0
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
test: ^1.15.7
|
test: ^1.17.8
|
||||||
|
pedantic: ^1.11.1
|
||||||
|
|
|
@ -2,15 +2,16 @@ import 'package:angel_http_exception/angel_http_exception.dart';
|
||||||
import 'package:angel_redis/angel_redis.dart';
|
import 'package:angel_redis/angel_redis.dart';
|
||||||
import 'package:resp_client/resp_client.dart';
|
import 'package:resp_client/resp_client.dart';
|
||||||
import 'package:resp_client/resp_commands.dart';
|
import 'package:resp_client/resp_commands.dart';
|
||||||
|
import 'package:resp_client/resp_server.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
main() async {
|
void main() async {
|
||||||
RespServerConnection connection;
|
late RespServerConnection connection;
|
||||||
RedisService service;
|
late RedisService service;
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
connection = await connectSocket('localhost');
|
connection = await connectSocket('localhost');
|
||||||
service = RedisService(RespCommands(RespClient(connection)),
|
service = RedisService(RespCommandsTier2(RespClient(connection)),
|
||||||
prefix: 'angel_redis_test');
|
prefix: 'angel_redis_test');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -36,7 +37,7 @@ main() async {
|
||||||
|
|
||||||
test('create without id', () async {
|
test('create without id', () async {
|
||||||
var input = {'bar': 'baz'};
|
var input = {'bar': 'baz'};
|
||||||
var output = await service.create(input);
|
var output = await (service.create(input));
|
||||||
print(output);
|
print(output);
|
||||||
expect(output.keys, contains('id'));
|
expect(output.keys, contains('id'));
|
||||||
expect(output, containsPair('bar', 'baz'));
|
expect(output, containsPair('bar', 'baz'));
|
||||||
|
|
12
packages/relations/AUTHORS.md
Normal file
12
packages/relations/AUTHORS.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Primary Authors
|
||||||
|
===============
|
||||||
|
|
||||||
|
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
||||||
|
|
||||||
|
Thomas is the current maintainer of the code base. He has refactored and migrated the
|
||||||
|
code base to support NNBD.
|
||||||
|
|
||||||
|
* __[Tobe O](thosakwe@gmail.com)__
|
||||||
|
|
||||||
|
Tobe has written much of the original code prior to NNBD migration. He has moved on and
|
||||||
|
is no longer involved with the project.
|
5
packages/relations/CHANGELOG.md
Normal file
5
packages/relations/CHANGELOG.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# 2.0.0
|
||||||
|
* Migrated to support Dart SDK 2.12.x NNBD
|
||||||
|
|
||||||
|
# 1.0.0
|
||||||
|
* Initial checkin
|
|
@ -1,4 +1,4 @@
|
||||||
MIT License (MIT)
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2021 dukefirehawk.com
|
Copyright (c) 2021 dukefirehawk.com
|
||||||
|
|
||||||
|
|
4
packages/relations/analysis_options.yaml
Normal file
4
packages/relations/analysis_options.yaml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
include: package:pedantic/analysis_options.yaml
|
||||||
|
analyzer:
|
||||||
|
strong-mode:
|
||||||
|
implicit-casts: false
|
|
@ -12,51 +12,44 @@ import 'no_service.dart';
|
||||||
/// * [localKey]: `userId`
|
/// * [localKey]: `userId`
|
||||||
/// * [foreignKey]: `id`
|
/// * [foreignKey]: `id`
|
||||||
HookedServiceEventListener belongsTo(Pattern servicePath,
|
HookedServiceEventListener belongsTo(Pattern servicePath,
|
||||||
{String as,
|
{String? as,
|
||||||
String foreignKey,
|
String? foreignKey,
|
||||||
String localKey,
|
String? localKey,
|
||||||
getForeignKey(obj),
|
Function(dynamic obj)? getForeignKey,
|
||||||
assignForeignObject(foreign, obj)}) {
|
Function(dynamic foreign, dynamic obj)? assignForeignObject}) {
|
||||||
String localId = localKey;
|
var localId = localKey;
|
||||||
var foreignName =
|
var foreignName =
|
||||||
as?.isNotEmpty == true ? as : pluralize.singular(servicePath.toString());
|
as?.isNotEmpty == true ? as! : pluralize.singular(servicePath.toString());
|
||||||
|
|
||||||
if (localId == null) {
|
localId ??= foreignName + 'Id';
|
||||||
localId = foreignName + 'Id';
|
|
||||||
// print('No local key provided for belongsTo, defaulting to \'$localId\'.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return (HookedServiceEvent e) async {
|
return (HookedServiceEvent e) async {
|
||||||
var ref = e.getService(servicePath);
|
var ref = e.getService(servicePath);
|
||||||
if (ref == null) throw noService(servicePath);
|
if (ref == null) throw noService(servicePath);
|
||||||
|
|
||||||
_getForeignKey(obj) {
|
dynamic _getForeignKey(obj) {
|
||||||
if (getForeignKey != null)
|
if (getForeignKey != null) {
|
||||||
return getForeignKey(obj);
|
return getForeignKey(obj);
|
||||||
else if (obj is Map)
|
} else if (obj is Map) {
|
||||||
return obj[localId];
|
return obj[localId];
|
||||||
//TODO: Undefined class
|
} else if (localId == null || localId == 'userId') {
|
||||||
//else if (obj is Extensible)
|
|
||||||
// return obj.properties[localId];
|
|
||||||
else if (localId == null || localId == 'userId')
|
|
||||||
return obj.userId;
|
return obj.userId;
|
||||||
else
|
} else {
|
||||||
return reflect(obj).getField(new Symbol(localId)).reflectee;
|
return reflect(obj).getField(Symbol(localId)).reflectee;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_assignForeignObject(foreign, obj) {
|
dynamic _assignForeignObject(foreign, obj) {
|
||||||
if (assignForeignObject != null)
|
if (assignForeignObject != null) {
|
||||||
return assignForeignObject(foreign, obj);
|
return assignForeignObject(foreign, obj);
|
||||||
else if (obj is Map)
|
} else if (obj is Map) {
|
||||||
obj[foreignName] = foreign;
|
obj[foreignName] = foreign;
|
||||||
//TODO: Undefined class
|
} else {
|
||||||
//else if (obj is Extensible)
|
reflect(obj).setField(Symbol(foreignName), foreign);
|
||||||
// obj.properties[foreignName] = foreign;
|
}
|
||||||
else
|
|
||||||
reflect(obj).setField(new Symbol(foreignName), foreign);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_normalize(obj) async {
|
Future _normalize(obj) async {
|
||||||
if (obj != null) {
|
if (obj != null) {
|
||||||
var id = await _getForeignKey(obj);
|
var id = await _getForeignKey(obj);
|
||||||
var indexed = await ref.index({
|
var indexed = await ref.index({
|
||||||
|
@ -73,8 +66,10 @@ HookedServiceEventListener belongsTo(Pattern servicePath,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.result is Iterable) {
|
if (e.result is Iterable) {
|
||||||
await Future.wait(e.result.map(_normalize));
|
//await Future.wait(e.result.map(_normalize));
|
||||||
} else
|
await e.result.map(_normalize);
|
||||||
|
} else {
|
||||||
await _normalize(e.result);
|
await _normalize(e.result);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,51 +12,44 @@ import 'no_service.dart';
|
||||||
/// * [foreignKey]: `userId`
|
/// * [foreignKey]: `userId`
|
||||||
/// * [localKey]: `id`
|
/// * [localKey]: `id`
|
||||||
HookedServiceEventListener belongsToMany(Pattern servicePath,
|
HookedServiceEventListener belongsToMany(Pattern servicePath,
|
||||||
{String as,
|
{String? as,
|
||||||
String foreignKey,
|
String? foreignKey,
|
||||||
String localKey,
|
String? localKey,
|
||||||
getForeignKey(obj),
|
Function(dynamic obj)? getForeignKey,
|
||||||
assignForeignObject(List foreign, obj)}) {
|
Function(dynamic foreign, dynamic obj)? assignForeignObject}) {
|
||||||
String localId = localKey;
|
var localId = localKey;
|
||||||
var foreignName =
|
var foreignName =
|
||||||
as?.isNotEmpty == true ? as : pluralize.plural(servicePath.toString());
|
as?.isNotEmpty == true ? as! : pluralize.plural(servicePath.toString());
|
||||||
|
|
||||||
if (localId == null) {
|
localId ??= foreignName + 'Id';
|
||||||
localId = foreignName + 'Id';
|
|
||||||
// print('No local key provided for belongsToMany, defaulting to \'$localId\'.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return (HookedServiceEvent e) async {
|
return (HookedServiceEvent e) async {
|
||||||
var ref = e.getService(servicePath);
|
var ref = e.getService(servicePath);
|
||||||
if (ref == null) throw noService(servicePath);
|
if (ref == null) throw noService(servicePath);
|
||||||
|
|
||||||
_getForeignKey(obj) {
|
dynamic _getForeignKey(obj) {
|
||||||
if (getForeignKey != null)
|
if (getForeignKey != null) {
|
||||||
return getForeignKey(obj);
|
return getForeignKey(obj);
|
||||||
else if (obj is Map)
|
} else if (obj is Map) {
|
||||||
return obj[localId];
|
return obj[localId];
|
||||||
//TODO: Undefined class
|
} else if (localId == null || localId == 'userId') {
|
||||||
//else if (obj is Extensible)
|
|
||||||
// return obj.properties[localId];
|
|
||||||
else if (localId == null || localId == 'userId')
|
|
||||||
return obj.userId;
|
return obj.userId;
|
||||||
else
|
} else {
|
||||||
return reflect(obj).getField(new Symbol(localId)).reflectee;
|
return reflect(obj).getField(Symbol(localId)).reflectee;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_assignForeignObject(foreign, obj) {
|
dynamic _assignForeignObject(foreign, obj) {
|
||||||
if (assignForeignObject != null)
|
if (assignForeignObject != null) {
|
||||||
return assignForeignObject(foreign, obj);
|
return assignForeignObject(foreign as List?, obj);
|
||||||
else if (obj is Map)
|
} else if (obj is Map) {
|
||||||
obj[foreignName] = foreign;
|
obj[foreignName] = foreign;
|
||||||
//TODO: Undefined class
|
} else {
|
||||||
//else if (obj is Extensible)
|
reflect(obj).setField(Symbol(foreignName), foreign);
|
||||||
// obj.properties[foreignName] = foreign;
|
}
|
||||||
else
|
|
||||||
reflect(obj).setField(new Symbol(foreignName), foreign);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_normalize(obj) async {
|
Future<void> _normalize(obj) async {
|
||||||
if (obj != null) {
|
if (obj != null) {
|
||||||
var id = await _getForeignKey(obj);
|
var id = await _getForeignKey(obj);
|
||||||
var indexed = await ref.index({
|
var indexed = await ref.index({
|
||||||
|
@ -73,8 +66,10 @@ HookedServiceEventListener belongsToMany(Pattern servicePath,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.result is Iterable) {
|
if (e.result is Iterable) {
|
||||||
await Future.wait(e.result.map(_normalize));
|
//await Future.wait(e.result.map(_normalize));
|
||||||
} else
|
await e.result.map(_normalize);
|
||||||
|
} else {
|
||||||
await _normalize(e.result);
|
await _normalize(e.result);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue