Merge branch 'sdk-2.12.x' into master
This commit is contained in:
commit
71b55f9548
273 changed files with 13958 additions and 2756 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -11,8 +11,10 @@
|
|||
.project
|
||||
.pub/
|
||||
.scripts-bin/
|
||||
.metals/
|
||||
build/
|
||||
**/packages/
|
||||
#**/packages/
|
||||
packages/hubbub/
|
||||
|
||||
# Files created by dart2js
|
||||
# (Most Dart developers will use pub build to compile Dart, use/modify these
|
||||
|
|
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"files.watcherExclude": {
|
||||
"**/target": true
|
||||
}
|
||||
}
|
56
CHANGELOG.md
Normal file
56
CHANGELOG.md
Normal file
|
@ -0,0 +1,56 @@
|
|||
# 3.0.1 (NNBD)
|
||||
* Changed Dart SDK requirements for all packages to ">=2.12.0 <3.0.0" to support NNBD.
|
||||
* Updated pretty_logging to 2.0.0
|
||||
* Updated angel_http_exception to 2.0.0
|
||||
* Updated angel_cli to 3.0.0. (Rename not working)
|
||||
|
||||
# 3.0.0 (Non NNBD)
|
||||
* Changed Dart SDK requirements for all packages to ">=2.10.0 <3.0.0"
|
||||
* Updated pretty_logging to 2.0.0
|
||||
* Updated angel_http_exception to 2.0.0
|
||||
* Updated angel_cli to 3.0.0. (Rename not working)
|
||||
* Updated angel_route to 4.0.0
|
||||
* Updated angel_model to 2.0.0
|
||||
* Updated angel_container to 2.0.0
|
||||
* Updated angel_framework to 3.0.0
|
||||
* Updated angel_auth to 3.0.0
|
||||
* Updated angel_configuration to 3.0.0
|
||||
* Updated jael to 3.0.0
|
||||
* Updated jael_preprocessor to 3.0.0
|
||||
* Updated validate to 3.0.0
|
||||
* Added and updated json_god to 3.0.0
|
||||
* Updated angel_client to 3.0.0
|
||||
* Updated angel_websocket to 3.0.0 (one issue to be resolved)
|
||||
* Updated test to 3.0.0
|
||||
* Updated angel_jael to 3.0.0 (Issue with 2 dependencies)
|
||||
* Added pub_sub and updated to 3.0.0
|
||||
* Updated production to 2.0.0
|
||||
* Updated hot to 3.0.0
|
||||
* Updated static to 3.0.0
|
||||
* Update basic-sdk-2.12.x boilerplate
|
||||
* Updated angel_serialize to 3.0.0
|
||||
* Updated angel_serialize_generator to 3.0.0
|
||||
* Updated angel_orm to 3.0.0
|
||||
* Updated angel_migration to 3.0.0
|
||||
* Updated angel_orm_generator to 3.0.0 (use a fork of postgres)
|
||||
* Updated angel_migration_runner to 3.0.0
|
||||
* Updated angel_orm_test to 1.0.0
|
||||
* Updated angel_orm_postgres to 2.0.0
|
||||
* Update orm-sdk-2.12.x boilerplate
|
||||
* Updated angel_auth_oauth2 to 3.0.0
|
||||
* Updated angel_auth_cache to 3.0.0
|
||||
* Updated angel_auth_cors to 3.0.0
|
||||
* Updated angel_container_generator to 2.0.0
|
||||
* Updated angel_file_service to 3.0.0
|
||||
* Updated angel_eventsource to 2.0.0 (use a fork of eventsource)
|
||||
* Updated angel_auth_twitter to 3.0.0 (use a fork of twitter and oauth)
|
||||
|
||||
# 2.2.0
|
||||
* Changed Dart SDK requirements for all packages to ">=2.10.0 <2.12.0"
|
||||
* Upgraded 3rd party libraries to the latest version prior to dart 2.12
|
||||
* Fixed broken code due to 3rd party libraries update
|
||||
* Revert packages/validate from version 3.0 to version 2.2
|
||||
|
||||
# 2.1.x and below
|
||||
* Refer to the orginal repo before the fork
|
||||
|
|
@ -73,6 +73,12 @@ dart --observe bin/dev.dart
|
|||
|
||||
Next, check out the [detailed documentation](https://docs.angel-dart.dev/v/2.x) to learn to flesh out your project.
|
||||
|
||||
## Development
|
||||
|
||||
* Install development version of Angel CLI
|
||||
`dart pub global activate --source path ./packages/cli`
|
||||
`dart pub global activate --source git https://github.com/dukefirehawk/angel/packages/cli`
|
||||
|
||||
## Examples and Documentation
|
||||
Visit the [documentation](https://docs.angel-dart.dev/v/2.x)
|
||||
for dozens of guides and resources, including video tutorials,
|
||||
|
|
9
TODO.md
Normal file
9
TODO.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Todo
|
||||
|
||||
### Container/angel_container_generator
|
||||
|
||||
* test/reflector_test.reflectab.dart - Changed ImplicitGetterMirrorImpl() from 5 to 3 parameters (revisit later)
|
||||
* A user forum
|
||||
* Updated User Guide
|
||||
|
||||
|
|
@ -1,21 +1,26 @@
|
|||
name: angel_auth
|
||||
description: A complete authentication plugin for Angel. Includes support for stateless JWT tokens, Basic Auth, and more.
|
||||
version: 2.1.5+1
|
||||
version: 3.0.0
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/angel_auth
|
||||
publish_to: none
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
sdk: ">=2.10.0 <3.0.0"
|
||||
dependencies:
|
||||
angel_framework: ^2.0.0-rc.6
|
||||
angel_framework:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/framework
|
||||
charcode: ^1.0.0
|
||||
collection: ^1.0.0
|
||||
crypto: ^2.0.0
|
||||
http_parser: ^3.0.0
|
||||
crypto: ^3.0.0
|
||||
http_parser: ^4.0.0
|
||||
meta: ^1.0.0
|
||||
quiver_hashcode: ^2.0.0
|
||||
dev_dependencies:
|
||||
http: ^0.12.0
|
||||
io: ^0.3.2
|
||||
logging: ^0.11.0
|
||||
http: ^0.13.0
|
||||
io: ^1.0.0
|
||||
logging: ^1.0.0
|
||||
pedantic: ^1.0.0
|
||||
test: ^1.0.0
|
||||
test: ^1.15.7
|
||||
|
|
|
@ -122,7 +122,7 @@ main() {
|
|||
});
|
||||
|
||||
test('login', () async {
|
||||
final response = await client.post('$url/login',
|
||||
final response = await client.post(Uri.parse('$url/login'),
|
||||
body: {'username': 'jdoe1', 'password': 'password'});
|
||||
print('Response: ${response.body}');
|
||||
expect(response.body, equals('Hello!'));
|
||||
|
@ -132,7 +132,7 @@ main() {
|
|||
: null);
|
||||
|
||||
test('preserve existing user', () async {
|
||||
final response = await client.post('$url/existing/foo',
|
||||
final response = await client.post(Uri.parse('$url/existing/foo'),
|
||||
body: {'username': 'jdoe1', 'password': 'password'},
|
||||
headers: {'accept': 'application/json'});
|
||||
print('Response: ${response.body}');
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'package:angel_auth/angel_auth.dart';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_framework/http.dart';
|
||||
|
@ -17,8 +16,9 @@ Map<String, String> sampleUser = {'hello': 'world'};
|
|||
Future<Map<String, String>> verifier(String username, String password) async {
|
||||
if (username == 'username' && password == 'password') {
|
||||
return sampleUser;
|
||||
} else
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future wireAuth(Angel app) async {
|
||||
|
@ -29,7 +29,7 @@ Future wireAuth(Angel app) async {
|
|||
await app.configure(auth.configureServer);
|
||||
}
|
||||
|
||||
main() async {
|
||||
void main() async {
|
||||
Angel app;
|
||||
AngelHttp angelHttp;
|
||||
http.Client client;
|
||||
|
@ -45,10 +45,10 @@ main() async {
|
|||
middleware: [auth.authenticate('local')]);
|
||||
app.post('/login', (req, res) => 'This should not be shown',
|
||||
middleware: [auth.authenticate('local', localOpts)]);
|
||||
app.get('/success', (req, res) => "yep", middleware: [
|
||||
app.get('/success', (req, res) => 'yep', middleware: [
|
||||
requireAuthentication<Map<String, String>>(),
|
||||
]);
|
||||
app.get('/failure', (req, res) => "nope");
|
||||
app.get('/failure', (req, res) => 'nope');
|
||||
|
||||
app.logger = Logger('angel_auth')
|
||||
..onRecord.listen((rec) {
|
||||
|
@ -58,10 +58,10 @@ main() async {
|
|||
}
|
||||
});
|
||||
|
||||
HttpServer server = await angelHttp.startServer('127.0.0.1', 0);
|
||||
url = "http://${server.address.host}:${server.port}";
|
||||
var server = await angelHttp.startServer('127.0.0.1', 0);
|
||||
url = 'http://${server.address.host}:${server.port}';
|
||||
basicAuthUrl =
|
||||
"http://username:password@${server.address.host}:${server.port}";
|
||||
'http://username:password@${server.address.host}:${server.port}';
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
|
@ -72,15 +72,15 @@ main() async {
|
|||
});
|
||||
|
||||
test('can use "auth" as middleware', () async {
|
||||
var response = await client
|
||||
.get("$url/success", headers: {'Accept': 'application/json'});
|
||||
var response = await client.get(Uri.parse('$url/success'),
|
||||
headers: {'Accept': 'application/json'});
|
||||
print(response.body);
|
||||
expect(response.statusCode, equals(403));
|
||||
});
|
||||
|
||||
test('successRedirect', () async {
|
||||
Map postData = {'username': 'username', 'password': 'password'};
|
||||
var response = await client.post("$url/login",
|
||||
var postData = {'username': 'username', 'password': 'password'};
|
||||
var response = await client.post(Uri.parse('$url/login'),
|
||||
body: json.encode(postData),
|
||||
headers: {'content-type': 'application/json'});
|
||||
expect(response.statusCode, equals(302));
|
||||
|
@ -88,24 +88,24 @@ main() async {
|
|||
});
|
||||
|
||||
test('failureRedirect', () async {
|
||||
Map postData = {'username': 'password', 'password': 'username'};
|
||||
var response = await client.post("$url/login",
|
||||
var postData = {'username': 'password', 'password': 'username'};
|
||||
var response = await client.post(Uri.parse('$url/login'),
|
||||
body: json.encode(postData),
|
||||
headers: {'content-type': 'application/json'});
|
||||
print("Login response: ${response.body}");
|
||||
print('Login response: ${response.body}');
|
||||
expect(response.headers['location'], equals('/failure'));
|
||||
expect(response.statusCode, equals(401));
|
||||
});
|
||||
|
||||
test('allow basic', () async {
|
||||
String authString = base64.encode("username:password".runes.toList());
|
||||
var response = await client
|
||||
.get("$url/hello", headers: {'authorization': 'Basic $authString'});
|
||||
var authString = base64.encode('username:password'.runes.toList());
|
||||
var response = await client.get(Uri.parse('$url/hello'),
|
||||
headers: {'authorization': 'Basic $authString'});
|
||||
expect(response.body, equals('"Woo auth"'));
|
||||
});
|
||||
|
||||
test('allow basic via URL encoding', () async {
|
||||
var response = await client.get("$basicAuthUrl/hello");
|
||||
var response = await client.get(Uri.parse('$basicAuthUrl/hello'));
|
||||
expect(response.body, equals('"Woo auth"'));
|
||||
});
|
||||
|
||||
|
@ -113,7 +113,7 @@ main() async {
|
|||
auth.strategies.clear();
|
||||
auth.strategies['local'] =
|
||||
LocalAuthStrategy(verifier, forceBasic: true, realm: 'test');
|
||||
var response = await client.get("$url/hello", headers: {
|
||||
var response = await client.get(Uri.parse('$url/hello'), headers: {
|
||||
'accept': 'application/json',
|
||||
'content-type': 'application/json'
|
||||
});
|
||||
|
|
|
@ -20,17 +20,18 @@ var options = ExternalAuthOptions(
|
|||
/// Github doesn't properly follow the OAuth2 spec, so here's logic to parse their response.
|
||||
Map<String, dynamic> parseParamsFromGithub(MediaType contentType, String body) {
|
||||
if (contentType.type == 'application') {
|
||||
if (contentType.subtype == 'x-www-form-urlencoded')
|
||||
if (contentType.subtype == 'x-www-form-urlencoded') {
|
||||
return Uri.splitQueryString(body);
|
||||
else if (contentType.subtype == 'json')
|
||||
} else if (contentType.subtype == 'json') {
|
||||
return (json.decode(body) as Map).cast<String, String>();
|
||||
}
|
||||
}
|
||||
|
||||
throw FormatException(
|
||||
'Invalid content-type $contentType; expected application/x-www-form-urlencoded or application/json.');
|
||||
}
|
||||
|
||||
main() async {
|
||||
void main() async {
|
||||
// Create the server instance.
|
||||
var app = Angel();
|
||||
var http = AngelHttp(app);
|
||||
|
@ -60,7 +61,7 @@ main() async {
|
|||
|
||||
// This function is called when the user ACCEPTS the request to sign in with Github.
|
||||
(client, req, res) async {
|
||||
var response = await client.get('https://api.github.com/user');
|
||||
var response = await client.get(Uri.parse('https://api.github.com/user'));
|
||||
var ghUser = json.decode(response.body);
|
||||
var id = ghUser['id'] as int;
|
||||
|
||||
|
|
|
@ -1,15 +1,24 @@
|
|||
name: angel_auth_oauth2
|
||||
description: angel_auth strategy for OAuth2 login, i.e. Facebook, Github, etc.
|
||||
version: 2.1.0
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
version: 3.0.0
|
||||
#author: Tobe O <thosakwe@gmail.com>
|
||||
publish_to: none
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
sdk: ">=2.10.0 <3.0.0"
|
||||
homepage: https://github.com/angel-dart/auth_oauth2.git
|
||||
dependencies:
|
||||
angel_auth: ^2.0.0
|
||||
angel_framework: ^2.0.0-alpha
|
||||
http_parser: ^3.0.0
|
||||
oauth2: ^1.0.0
|
||||
angel_auth:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/auth
|
||||
angel_framework:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/framework
|
||||
http_parser: ^4.0.0
|
||||
oauth2: ^2.0.0
|
||||
dev_dependencies:
|
||||
logging: ^0.11.0
|
||||
logging: ^1.0.0
|
||||
pedantic: ^1.0.0
|
|
@ -1,20 +1,28 @@
|
|||
author: "Tobe O <thosakwe@gmail.com>"
|
||||
name: "angel_auth_twitter"
|
||||
#author: "Tobe O <thosakwe@gmail.com>"
|
||||
description: "package:angel_auth strategy for Twitter login. Auto-signs requests."
|
||||
environment:
|
||||
sdk: ">=2.0.0 <3.0.0"
|
||||
sdk: ">=2.10.0 <3.0.0"
|
||||
homepage: "https://github.com/angel-dart/auth_twitter.git"
|
||||
name: "angel_auth_twitter"
|
||||
version: 2.0.0
|
||||
version: 3.0.0
|
||||
publish_to: none
|
||||
dependencies:
|
||||
angel_auth: ^2.0.0
|
||||
angel_framework: ^2.0.0-alpha
|
||||
http: ">=0.11.0 <0.13.0"
|
||||
angel_auth:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/auth
|
||||
angel_framework:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/framework
|
||||
http: ^0.13.0
|
||||
path: ^1.0.0
|
||||
# oauth:
|
||||
# git:
|
||||
# url: git://github.com/sh4869/oauth.dart.git
|
||||
# ref: develop
|
||||
twitter: ^1.0.0
|
||||
twitter:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/twitter.dart.git
|
||||
ref: sdk-2.12.x
|
||||
dev_dependencies:
|
||||
logging: ^0.11.0
|
||||
pedantic: ^1.0.0
|
||||
logging: ^1.0.0
|
||||
pedantic: ^1.11.0
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
import 'package:http_parser/http_parser.dart';
|
||||
import 'package:body_parser/body_parser.dart';
|
||||
|
||||
main() async {
|
||||
|
@ -23,12 +24,20 @@ main() async {
|
|||
|
||||
void start(List args) {
|
||||
var address = new InternetAddress(args[0] as String);
|
||||
int port = args[1], id = args[2];
|
||||
int port = 8080;
|
||||
if (args[1] is int) {
|
||||
args[1];
|
||||
}
|
||||
|
||||
int id = 0;
|
||||
if (args[2] is int) {
|
||||
args[2];
|
||||
}
|
||||
|
||||
HttpServer.bind(address, port, shared: true).then((server) {
|
||||
server.listen((request) async {
|
||||
// ignore: deprecated_member_use
|
||||
var body = await parseBody(request);
|
||||
var body = await defaultParseBody(request);
|
||||
request.response
|
||||
..headers.contentType = new ContentType('application', 'json')
|
||||
..write(json.encode(body.body))
|
||||
|
@ -39,3 +48,14 @@ void start(List args) {
|
|||
'Server #$id listening at http://${server.address.address}:${server.port}');
|
||||
});
|
||||
}
|
||||
|
||||
Future<BodyParseResult> defaultParseBody(HttpRequest request,
|
||||
{bool storeOriginalBuffer: false}) {
|
||||
return parseBodyFromStream(
|
||||
request,
|
||||
request.headers.contentType != null
|
||||
? new MediaType.parse(request.headers.contentType.toString())
|
||||
: null,
|
||||
request.uri,
|
||||
storeOriginalBuffer: storeOriginalBuffer);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ version: 1.1.1
|
|||
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
|
||||
environment:
|
||||
sdk: ">=1.8.0 <3.0.0"
|
||||
sdk: ">=2.10.0 <2.12.0"
|
||||
dependencies:
|
||||
dart2_constant: ^1.0.0
|
||||
http_parser: ">=3.1.1 <4.0.0"
|
||||
|
@ -12,4 +12,4 @@ dependencies:
|
|||
mime: ">=0.9.3 <1.0.0"
|
||||
dev_dependencies:
|
||||
http: ">=0.11.3 <0.12.0"
|
||||
test: ">=0.12.15"
|
||||
test: ^1.15.7
|
|
@ -1,11 +1,12 @@
|
|||
import 'dart:io';
|
||||
import 'dart:convert';
|
||||
import 'package:body_parser/body_parser.dart';
|
||||
import 'package:dart2_constant/convert.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:test/test.dart';
|
||||
import 'server_test.dart';
|
||||
|
||||
main() {
|
||||
void main() {
|
||||
HttpServer server;
|
||||
String url;
|
||||
http.Client client;
|
||||
|
@ -20,7 +21,7 @@ main() {
|
|||
});
|
||||
url = 'http://localhost:${server.port}';
|
||||
print('Test server listening on $url');
|
||||
client = new http.Client();
|
||||
client = http.Client();
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
|
@ -49,7 +50,7 @@ world
|
|||
'Form Data: \n${postData.replaceAll("\r", "\\r").replaceAll("\n", "\\n")}');
|
||||
var response = await client.post(url, headers: headers, body: postData);
|
||||
print('Response: ${response.body}');
|
||||
Map jsons = json.decode(response.body);
|
||||
var jsons = json.decode(response.body);
|
||||
var files = jsons['files'].map((map) {
|
||||
return map == null
|
||||
? null
|
||||
|
@ -63,7 +64,7 @@ world
|
|||
test('Single upload', () async {
|
||||
String boundary = 'myBoundary';
|
||||
Map<String, String> headers = {
|
||||
'content-type': new ContentType("multipart", "form-data",
|
||||
'content-type': ContentType("multipart", "form-data",
|
||||
parameters: {"boundary": boundary}).toString()
|
||||
};
|
||||
String postData = '''
|
||||
|
@ -84,7 +85,7 @@ Hello world
|
|||
'Form Data: \n${postData.replaceAll("\r", "\\r").replaceAll("\n", "\\n")}');
|
||||
var response = await client.post(url, headers: headers, body: postData);
|
||||
print('Response: ${response.body}');
|
||||
Map jsons = json.decode(response.body);
|
||||
var jsons = json.decode(response.body);
|
||||
var files = jsons['files'];
|
||||
expect(files.length, equals(1));
|
||||
expect(files[0]['name'], equals('file'));
|
||||
|
@ -128,7 +129,7 @@ function main() {
|
|||
'Form Data: \n${postData.replaceAll("\r", "\\r").replaceAll("\n", "\\n")}');
|
||||
var response = await client.post(url, headers: headers, body: postData);
|
||||
print('Response: ${response.body}');
|
||||
Map jsons = json.decode(response.body);
|
||||
var jsons = json.decode(response.body);
|
||||
var files = jsons['files'];
|
||||
expect(files.length, equals(2));
|
||||
expect(files[0]['name'], equals('file'));
|
||||
|
|
|
@ -26,7 +26,7 @@ String jsonEncodeBody(BodyParseResult result) {
|
|||
});
|
||||
}
|
||||
|
||||
main() {
|
||||
void main() {
|
||||
HttpServer server;
|
||||
String url;
|
||||
http.Client client;
|
||||
|
@ -42,7 +42,7 @@ main() {
|
|||
});
|
||||
url = 'http://localhost:${server.port}';
|
||||
print('Test server listening on $url');
|
||||
client = new http.Client();
|
||||
client = http.Client();
|
||||
});
|
||||
tearDown(() async {
|
||||
await server.close(force: true);
|
||||
|
|
11
packages/cache/example/cache_service.dart
vendored
11
packages/cache/example/cache_service.dart
vendored
|
@ -1,14 +1,15 @@
|
|||
import 'package:angel_cache/angel_cache.dart';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_framework/http.dart';
|
||||
|
||||
main() async {
|
||||
var app = new Angel();
|
||||
var app = Angel();
|
||||
|
||||
app.use(
|
||||
'/api/todos',
|
||||
new CacheService(
|
||||
cache: new MapService(),
|
||||
database: new AnonymousService(index: ([params]) {
|
||||
CacheService(
|
||||
cache: MapService(),
|
||||
database: AnonymousService(index: ([params]) {
|
||||
print(
|
||||
'Fetched directly from the underlying service at ${new DateTime.now()}!');
|
||||
return ['foo', 'bar', 'baz'];
|
||||
|
@ -18,7 +19,7 @@ main() async {
|
|||
),
|
||||
);
|
||||
|
||||
var http = new AngelHttp(app);
|
||||
var http = AngelHttp(app);
|
||||
var server = await http.startServer('127.0.0.1', 3000);
|
||||
print('Listening at http://${server.address.address}:${server.port}');
|
||||
}
|
||||
|
|
15
packages/cache/example/main.dart
vendored
15
packages/cache/example/main.dart
vendored
|
@ -1,26 +1,27 @@
|
|||
import 'package:angel_cache/angel_cache.dart';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_framework/http.dart';
|
||||
import 'package:glob/glob.dart';
|
||||
|
||||
main() async {
|
||||
var app = new Angel();
|
||||
var app = Angel();
|
||||
|
||||
// Cache a glob
|
||||
var cache = new ResponseCache()
|
||||
var cache = ResponseCache()
|
||||
..patterns.addAll([
|
||||
new Glob('/*.txt'),
|
||||
Glob('/*.txt'),
|
||||
]);
|
||||
|
||||
// Handle `if-modified-since` header, and also send cached content
|
||||
app.fallback(cache.handleRequest);
|
||||
|
||||
// A simple handler that returns a different result every time.
|
||||
app.get('/date.txt',
|
||||
(req, res) => res.write(new DateTime.now().toIso8601String()));
|
||||
app.get(
|
||||
'/date.txt', (req, res) => res.write(DateTime.now().toIso8601String()));
|
||||
|
||||
// Support purging the cache.
|
||||
app.addRoute('PURGE', '*', (req, res) {
|
||||
if (req.ip != '127.0.0.1') throw new AngelHttpException.forbidden();
|
||||
if (req.ip != '127.0.0.1') throw AngelHttpException.forbidden();
|
||||
|
||||
cache.purge(req.uri.path);
|
||||
print('Purged ${req.uri.path}');
|
||||
|
@ -29,7 +30,7 @@ main() async {
|
|||
// The response finalizer that actually saves the content
|
||||
app.responseFinalizers.add(cache.responseFinalizer);
|
||||
|
||||
var http = new AngelHttp(app);
|
||||
var http = AngelHttp(app);
|
||||
var server = await http.startServer('127.0.0.1', 3000);
|
||||
print('Listening at http://${server.address.address}:${server.port}');
|
||||
}
|
||||
|
|
10
packages/cache/lib/src/serializer.dart
vendored
10
packages/cache/lib/src/serializer.dart
vendored
|
@ -12,11 +12,13 @@ RequestHandler cacheSerializationResults(
|
|||
shouldCache}) {
|
||||
return (RequestContext req, ResponseContext res) async {
|
||||
var oldSerializer = res.serializer;
|
||||
var cache = <dynamic, String>{};
|
||||
|
||||
// TODO: Commented out as it is not doing anything useful
|
||||
//var cache = <dynamic, String>{};
|
||||
res.serializer = (value) {
|
||||
if (shouldCache == null) {
|
||||
return cache.putIfAbsent(value, () => oldSerializer(value));
|
||||
}
|
||||
//if (shouldCache == null) {
|
||||
// return cache.putIfAbsent(value, () => oldSerializer(value));
|
||||
//}
|
||||
|
||||
return oldSerializer(value);
|
||||
};
|
||||
|
|
23
packages/cache/pubspec.yaml
vendored
23
packages/cache/pubspec.yaml
vendored
|
@ -1,17 +1,26 @@
|
|||
name: angel_cache
|
||||
version: 2.0.1
|
||||
version: 3.0.0
|
||||
homepage: https://github.com/angel-dart/cache
|
||||
description: Support for server-side caching in Angel.
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
publish_to: none
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
sdk: ">=2.10.0 <3.0.0"
|
||||
dependencies:
|
||||
angel_framework: ^2.0.0-alpha
|
||||
angel_framework:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/framework
|
||||
collection: ^1.0.0
|
||||
meta: ^1.0.0
|
||||
pool: ^1.0.0
|
||||
dev_dependencies:
|
||||
angel_test: ^2.0.0-alpha
|
||||
glob: ^1.0.0
|
||||
http: any
|
||||
test: ^1.0.0
|
||||
angel_test:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/test
|
||||
glob: ^2.0.0
|
||||
http: ^0.13.0
|
||||
test: ^1.16.5
|
10
packages/cache/test/cache_test.dart
vendored
10
packages/cache/test/cache_test.dart
vendored
|
@ -42,8 +42,8 @@ main() async {
|
|||
};
|
||||
|
||||
client = await connectTo(app);
|
||||
response1 = await client.get('/date.txt');
|
||||
response2 = await client.get('/date.txt');
|
||||
response1 = await client.get(Uri.parse('/date.txt'));
|
||||
response2 = await client.get(Uri.parse('/date.txt'));
|
||||
print(response2.headers);
|
||||
lastModified = HttpDate.parse(response2.headers['last-modified']);
|
||||
print('Response 1 status: ${response1.statusCode}');
|
||||
|
@ -76,7 +76,7 @@ main() async {
|
|||
|
||||
test('invalidate', () async {
|
||||
await client.sendUnstreamed('PURGE', '/date.txt', {});
|
||||
var response = await client.get('/date.txt');
|
||||
var response = await client.get(Uri.parse('/date.txt'));
|
||||
print('Response after invalidation: ${response.body}');
|
||||
expect(response.body, isNot(response1.body));
|
||||
});
|
||||
|
@ -86,14 +86,14 @@ main() async {
|
|||
'if-modified-since':
|
||||
HttpDate.format(lastModified.add(const Duration(days: 1)))
|
||||
};
|
||||
var response = await client.get('/date.txt', headers: headers);
|
||||
var response = await client.get(Uri.parse('/date.txt'), headers: headers);
|
||||
print('Sending headers: $headers');
|
||||
print('Response (${response.statusCode}): ${response.headers}');
|
||||
expect(response.statusCode, 304);
|
||||
});
|
||||
|
||||
test('last-modified in the past', () async {
|
||||
var response = await client.get('/date.txt', headers: {
|
||||
var response = await client.get(Uri.parse('/date.txt'), headers: {
|
||||
'if-modified-since':
|
||||
HttpDate.format(lastModified.subtract(const Duration(days: 10)))
|
||||
});
|
||||
|
|
|
@ -9,12 +9,16 @@ Includes functionality such as:
|
|||
* Renaming projects
|
||||
* Much more...
|
||||
|
||||
To install:
|
||||
* To install:
|
||||
|
||||
```bash
|
||||
$ pub global activate angel_cli
|
||||
```
|
||||
|
||||
* Install development version
|
||||
`dart pub global activate --source path ./packages/cli`
|
||||
`dart pub global activate --source git https://github.com/dukefirehawk/angel/packages/cli`
|
||||
|
||||
And then, for information on each command:
|
||||
|
||||
```bash
|
||||
|
|
|
@ -11,7 +11,7 @@ class DeployCommand extends Command {
|
|||
'Generates scaffolding + helper functionality for deploying servers. Run this in your project root.';
|
||||
|
||||
DeployCommand() {
|
||||
addSubcommand(new NginxCommand());
|
||||
addSubcommand(new SystemdCommand());
|
||||
addSubcommand(NginxCommand());
|
||||
addSubcommand(SystemdCommand());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ class DoctorCommand extends Command {
|
|||
print(green.wrap(
|
||||
"$checkmark Git executable found: v${version.replaceAll('git version', '').trim()}"));
|
||||
} else
|
||||
throw new Exception("Git executable exit code not 0");
|
||||
throw Exception("Git executable exit code not 0");
|
||||
} catch (exc) {
|
||||
print(red.wrap("$ballot Git executable not found"));
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import 'pub.dart';
|
|||
import 'rename.dart';
|
||||
|
||||
class InitCommand extends Command {
|
||||
final KeyCommand _key = new KeyCommand();
|
||||
final KeyCommand _key = KeyCommand();
|
||||
|
||||
@override
|
||||
String get name => "init";
|
||||
|
@ -35,21 +35,19 @@ class InitCommand extends Command {
|
|||
@override
|
||||
run() async {
|
||||
Directory projectDir =
|
||||
new Directory(argResults.rest.isEmpty ? "." : argResults.rest[0]);
|
||||
Directory(argResults.rest.isEmpty ? "." : argResults.rest[0]);
|
||||
print("Creating new Angel project in ${projectDir.absolute.path}...");
|
||||
await _cloneRepo(projectDir);
|
||||
// await preBuild(projectDir);
|
||||
var secret = rs.randomAlphaNumeric(32);
|
||||
print('Generated new development JWT secret: $secret');
|
||||
await _key.changeSecret(
|
||||
new File.fromUri(projectDir.uri.resolve('config/default.yaml')),
|
||||
secret);
|
||||
File.fromUri(projectDir.uri.resolve('config/default.yaml')), secret);
|
||||
|
||||
secret = rs.randomAlphaNumeric(32);
|
||||
print('Generated new production JWT secret: $secret');
|
||||
await _key.changeSecret(
|
||||
new File.fromUri(projectDir.uri.resolve('config/production.yaml')),
|
||||
secret);
|
||||
File.fromUri(projectDir.uri.resolve('config/production.yaml')), secret);
|
||||
|
||||
var name = argResults.wasParsed('project-name')
|
||||
? argResults['project-name'] as String
|
||||
|
@ -110,9 +108,9 @@ class InitCommand extends Command {
|
|||
|
||||
switch (stat.type) {
|
||||
case FileSystemEntityType.directory:
|
||||
return await _deleteRecursive(new Directory(path));
|
||||
return await _deleteRecursive(Directory(path));
|
||||
case FileSystemEntityType.file:
|
||||
return await _deleteRecursive(new File(path));
|
||||
return await _deleteRecursive(File(path));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -198,7 +196,7 @@ class InitCommand extends Command {
|
|||
}
|
||||
|
||||
if (await git.exitCode != 0) {
|
||||
throw new Exception("Could not clone repo.");
|
||||
throw Exception("Could not clone repo.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,7 +222,7 @@ class InitCommand extends Command {
|
|||
await preBuild(projectDir).catchError((_) => null);
|
||||
}
|
||||
|
||||
var gitDir = new Directory.fromUri(projectDir.uri.resolve(".git"));
|
||||
var gitDir = Directory.fromUri(projectDir.uri.resolve(".git"));
|
||||
if (await gitDir.exists()) await gitDir.delete(recursive: true);
|
||||
} catch (e) {
|
||||
await boilerplateDir.delete(recursive: true).catchError((_) => null);
|
||||
|
@ -260,44 +258,48 @@ Future preBuild(Directory projectDir) async {
|
|||
|
||||
var buildCode = await build.exitCode;
|
||||
|
||||
if (buildCode != 0) throw new Exception('Failed to pre-build resources.');
|
||||
if (buildCode != 0) throw Exception('Failed to pre-build resources.');
|
||||
}
|
||||
|
||||
const RepoArchiveLocation = "https://github.com/angel-dart";
|
||||
const RepoLocation = "https://github.com/dukefirehawk";
|
||||
|
||||
const BoilerplateInfo graphQLBoilerplate = const BoilerplateInfo(
|
||||
'GraphQL',
|
||||
"A starting point for GraphQL API servers.",
|
||||
'https://github.com/angel-dart/angel.git',
|
||||
ref: 'graphql',
|
||||
'${RepoLocation}/boilerplates.git',
|
||||
ref: 'graphql-sdk-2.12.x',
|
||||
);
|
||||
|
||||
const BoilerplateInfo ormBoilerplate = const BoilerplateInfo(
|
||||
'ORM',
|
||||
"A starting point for applications that use Angel's ORM.",
|
||||
'https://github.com/angel-dart/angel.git',
|
||||
ref: 'orm',
|
||||
'${RepoLocation}/boilerplates.git',
|
||||
ref: 'orm-sdk-2.12.x',
|
||||
);
|
||||
|
||||
const BoilerplateInfo basicBoilerplate = const BoilerplateInfo(
|
||||
'Basic',
|
||||
'Minimal starting point for Angel 2.x - A simple server with only a few additional packages.',
|
||||
'https://github.com/angel-dart/angel.git');
|
||||
'${RepoLocation}/boilerplates.git',
|
||||
ref: 'basic-sdk-2.12.x');
|
||||
|
||||
const BoilerplateInfo legacyBoilerplate = const BoilerplateInfo(
|
||||
'Legacy',
|
||||
'Minimal starting point for applications running Angel 1.1.x.',
|
||||
'https://github.com/angel-dart/angel.git',
|
||||
'${RepoArchiveLocation}/angel.git',
|
||||
ref: '1.1.x',
|
||||
);
|
||||
|
||||
const BoilerplateInfo sharedBoilerplate = const BoilerplateInfo(
|
||||
'Shared',
|
||||
'Holds common models and files shared across multiple Dart projects.',
|
||||
'https://github.com/angel-dart/boilerplate_shared.git');
|
||||
'${RepoLocation}/boilerplate_shared.git');
|
||||
|
||||
const BoilerplateInfo sharedOrmBoilerplate = const BoilerplateInfo(
|
||||
'Shared (ORM)',
|
||||
'Holds common models and files shared across multiple Dart projects.',
|
||||
'https://github.com/angel-dart/boilerplate_shared.git',
|
||||
'${RepoLocation}/boilerplate_shared.git',
|
||||
ref: 'orm',
|
||||
);
|
||||
|
||||
|
@ -306,8 +308,8 @@ const List<BoilerplateInfo> boilerplates = const [
|
|||
//legacyBoilerplate,
|
||||
ormBoilerplate,
|
||||
graphQLBoilerplate,
|
||||
sharedBoilerplate,
|
||||
sharedOrmBoilerplate,
|
||||
//sharedBoilerplate,
|
||||
//sharedOrmBoilerplate,
|
||||
];
|
||||
|
||||
class BoilerplateInfo {
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'dart:io';
|
|||
import 'package:args/command_runner.dart';
|
||||
import 'package:glob/glob.dart';
|
||||
import 'package:io/ansi.dart';
|
||||
import 'package:mustache4dart/mustache4dart.dart' as mustache;
|
||||
import 'package:mustache4dart2/mustache4dart2.dart' as mustache;
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:prompts/prompts.dart' as prompts;
|
||||
import 'package:pubspec_parse/pubspec_parse.dart';
|
||||
|
@ -14,7 +14,7 @@ import 'make/maker.dart';
|
|||
class InstallCommand extends Command {
|
||||
static const String repo = 'https://github.com/angel-dart/install.git';
|
||||
static final Directory installRepo =
|
||||
new Directory.fromUri(homeDir.uri.resolve('./.angel/addons'));
|
||||
Directory.fromUri(homeDir.uri.resolve('./.angel/addons'));
|
||||
|
||||
@override
|
||||
String get name => 'install';
|
||||
|
@ -72,7 +72,7 @@ class InstallCommand extends Command {
|
|||
|
||||
for (var packageName in argResults.rest) {
|
||||
var packageDir =
|
||||
new Directory.fromUri(installRepo.uri.resolve(packageName));
|
||||
Directory.fromUri(installRepo.uri.resolve(packageName));
|
||||
|
||||
if (!await packageDir.exists())
|
||||
throw 'No add-on named "$packageName" is installed. You might need to run `angel install --update`.';
|
||||
|
@ -90,7 +90,7 @@ class InstallCommand extends Command {
|
|||
.map((k) {
|
||||
var dep = projectPubspec.dependencies[k];
|
||||
if (dep is HostedDependency)
|
||||
return new MakerDependency(k, dep.version.toString());
|
||||
return MakerDependency(k, dep.version.toString());
|
||||
return null;
|
||||
})
|
||||
.where((d) => d != null)
|
||||
|
@ -99,14 +99,13 @@ class InstallCommand extends Command {
|
|||
deps.addAll(projectPubspec.devDependencies.keys.map((k) {
|
||||
var dep = projectPubspec.devDependencies[k];
|
||||
if (dep is HostedDependency)
|
||||
return new MakerDependency(k, dep.version.toString(), dev: true);
|
||||
return MakerDependency(k, dep.version.toString(), dev: true);
|
||||
return null;
|
||||
}).where((d) => d != null));
|
||||
|
||||
await depend(deps);
|
||||
|
||||
var promptFile =
|
||||
new File.fromUri(packageDir.uri.resolve('angel_cli.yaml'));
|
||||
var promptFile = File.fromUri(packageDir.uri.resolve('angel_cli.yaml'));
|
||||
|
||||
if (await promptFile.exists()) {
|
||||
var contents = await promptFile.readAsString();
|
||||
|
@ -116,7 +115,7 @@ class InstallCommand extends Command {
|
|||
// Loads globs
|
||||
if (cfg['templates'] is List) {
|
||||
globs.addAll(
|
||||
(cfg['templates'] as List).map((p) => new Glob(p.toString())));
|
||||
(cfg['templates'] as List).map((p) => Glob(p.toString())));
|
||||
}
|
||||
|
||||
if (cfg['values'] is Map) {
|
||||
|
@ -144,14 +143,14 @@ class InstallCommand extends Command {
|
|||
await for (var entity in src.list()) {
|
||||
if (entity is Directory) {
|
||||
var name = p.basename(entity.path);
|
||||
var newDir = new Directory.fromUri(dst.uri.resolve(name));
|
||||
var newDir = Directory.fromUri(dst.uri.resolve(name));
|
||||
await merge(
|
||||
entity, newDir, prefix.isEmpty ? name : '$prefix/$name');
|
||||
} else if (entity is File &&
|
||||
!entity.path.endsWith('angel_cli.yaml')) {
|
||||
var name = p.basename(entity.path);
|
||||
var target = dst.uri.resolve(name);
|
||||
var targetFile = new File.fromUri(target);
|
||||
var targetFile = File.fromUri(target);
|
||||
bool allClear = !await targetFile.exists();
|
||||
|
||||
if (!allClear) {
|
||||
|
@ -187,7 +186,7 @@ class InstallCommand extends Command {
|
|||
}
|
||||
}
|
||||
|
||||
await merge(new Directory.fromUri(packageDir.uri.resolve('files')),
|
||||
await merge(Directory.fromUri(packageDir.uri.resolve('files')),
|
||||
Directory.current, '');
|
||||
print('Successfully installed $packageName@${projectPubspec.version}.');
|
||||
}
|
||||
|
|
|
@ -13,17 +13,17 @@ class KeyCommand extends Command {
|
|||
run() async {
|
||||
var secret = rs.randomAlphaNumeric(32);
|
||||
print('Generated new development JWT secret: $secret');
|
||||
await changeSecret(new File('config/default.yaml'), secret);
|
||||
await changeSecret(File('config/default.yaml'), secret);
|
||||
|
||||
secret = rs.randomAlphaNumeric(32);
|
||||
print('Generated new production JWT secret: $secret');
|
||||
await changeSecret(new File('config/production.yaml'), secret);
|
||||
await changeSecret(File('config/production.yaml'), secret);
|
||||
}
|
||||
|
||||
changeSecret(File file, String secret) async {
|
||||
if (await file.exists()) {
|
||||
var contents = await file.readAsString();
|
||||
contents = contents.replaceAll(new RegExp(r'jwt_secret:[^\n]+\n?'), '');
|
||||
contents = contents.replaceAll(RegExp(r'jwt_secret:[^\n]+\n?'), '');
|
||||
await file.writeAsString(contents.trim() + '\njwt_secret: "$secret"');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,11 @@ class MakeCommand extends Command {
|
|||
'Generates common code for your project, such as projects and controllers.';
|
||||
|
||||
MakeCommand() {
|
||||
addSubcommand(new ControllerCommand());
|
||||
addSubcommand(new MigrationCommand());
|
||||
addSubcommand(new ModelCommand());
|
||||
addSubcommand(new PluginCommand());
|
||||
addSubcommand(new TestCommand());
|
||||
addSubcommand(new ServiceCommand());
|
||||
addSubcommand(ControllerCommand());
|
||||
addSubcommand(MigrationCommand());
|
||||
addSubcommand(ModelCommand());
|
||||
addSubcommand(PluginCommand());
|
||||
addSubcommand(TestCommand());
|
||||
addSubcommand(ServiceCommand());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ class ControllerCommand extends Command {
|
|||
const MakerDependency('angel_framework', '^2.0.0')
|
||||
];
|
||||
|
||||
// ${pubspec.name}.src.models.${rc.snakeCase}
|
||||
//${pubspec.name}.src.models.${rc.snakeCase}
|
||||
|
||||
var rc = new ReCase(name);
|
||||
var controllerLib = new Library((controllerLib) {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import 'dart:io';
|
||||
|
||||
final RegExp _leadingSlashes = new RegExp(r'^/+');
|
||||
final RegExp _leadingSlashes = RegExp(r'^/+');
|
||||
|
||||
String resolvePub() {
|
||||
var exec = new File(Platform.resolvedExecutable);
|
||||
var exec = File(Platform.resolvedExecutable);
|
||||
var pubPath = exec.parent.uri.resolve('pub').path;
|
||||
if (Platform.isWindows)
|
||||
pubPath = pubPath.replaceAll(_leadingSlashes, '') + '.bat';
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import 'dart:io';
|
||||
import 'package:analyzer/analyzer.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/dart/ast/visitor.dart';
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:dart_style/dart_style.dart';
|
||||
import 'package:glob/glob.dart';
|
||||
import 'package:glob/list_local_fs.dart';
|
||||
import 'package:io/ansi.dart';
|
||||
import 'package:prompts/prompts.dart' as prompts;
|
||||
import 'package:recase/recase.dart';
|
||||
|
@ -14,7 +16,7 @@ class RenameCommand extends Command {
|
|||
String get name => 'rename';
|
||||
|
||||
@override
|
||||
String get description => 'Renames the current project.';
|
||||
String get description => 'Renames the current project (To be available).';
|
||||
|
||||
@override
|
||||
String get invocation => '$name <new name>';
|
||||
|
@ -29,17 +31,20 @@ class RenameCommand extends Command {
|
|||
newName = prompts.get('Rename project to');
|
||||
}
|
||||
|
||||
newName = new ReCase(newName).snakeCase;
|
||||
newName = ReCase(newName).snakeCase;
|
||||
|
||||
var choice = prompts.getBool('Rename the project to `$newName`?');
|
||||
|
||||
// TODO: To be available once the issue is fixed
|
||||
if (choice) {
|
||||
print('Rename the project is currently not available');
|
||||
/*
|
||||
print('Renaming project to `$newName`...');
|
||||
var pubspecFile =
|
||||
new File.fromUri(Directory.current.uri.resolve('pubspec.yaml'));
|
||||
File.fromUri(Directory.current.uri.resolve('pubspec.yaml'));
|
||||
|
||||
if (!await pubspecFile.exists()) {
|
||||
throw new Exception('No pubspec.yaml found in current directory.');
|
||||
throw Exception('No pubspec.yaml found in current directory.');
|
||||
} else {
|
||||
var pubspec = await loadPubspec();
|
||||
var oldName = pubspec.name;
|
||||
|
@ -53,6 +58,7 @@ class RenameCommand extends Command {
|
|||
stderr.addStream(pub.stderr);
|
||||
await pub.exitCode;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,12 +67,12 @@ renamePubspec(Directory dir, String oldName, String newName) async {
|
|||
// var pubspec = await loadPubspec(dir);
|
||||
print(cyan.wrap('Renaming your project to `$newName.`'));
|
||||
|
||||
var pubspecFile = new File.fromUri(dir.uri.resolve('pubspec.yaml'));
|
||||
var pubspecFile = File.fromUri(dir.uri.resolve('pubspec.yaml'));
|
||||
|
||||
if (await pubspecFile.exists()) {
|
||||
var contents = await pubspecFile.readAsString(), oldContents = contents;
|
||||
contents =
|
||||
contents.replaceAll(new RegExp('name:\\s*$oldName'), 'name: $newName');
|
||||
contents.replaceAll(RegExp('name:\\s*$oldName'), 'name: $newName');
|
||||
|
||||
if (contents != oldContents) {
|
||||
await pubspecFile.writeAsString(contents);
|
||||
|
@ -76,7 +82,7 @@ renamePubspec(Directory dir, String oldName, String newName) async {
|
|||
// print(cyan
|
||||
// .wrap('Note that this does not actually modify your `pubspec.yaml`.'));
|
||||
// TODO: https://github.com/dart-lang/pubspec_parse/issues/17
|
||||
// var newPubspec = new Pubspec.fromJson(pubspec.toJson()..['name'] = newName);
|
||||
// var newPubspec = Pubspec.fromJson(pubspec.toJson()..['name'] = newName);
|
||||
// await newPubspec.save(dir);
|
||||
}
|
||||
|
||||
|
@ -84,34 +90,39 @@ renameDartFiles(Directory dir, String oldName, String newName) async {
|
|||
if (!await dir.exists()) return;
|
||||
|
||||
// Try to replace MongoDB URL
|
||||
var configGlob = new Glob('config/**/*.yaml');
|
||||
var configGlob = Glob('config/**/*.yaml');
|
||||
|
||||
try {
|
||||
await for (var yamlFile in configGlob.list(root: dir.absolute.path)) {
|
||||
if (yamlFile is File) {
|
||||
print(
|
||||
'Replacing occurrences of "$oldName" with "$newName" in file "${yamlFile.absolute.path}"...');
|
||||
var contents = await yamlFile.readAsString();
|
||||
if (yamlFile is File) {
|
||||
var contents = (yamlFile as File).readAsStringSync();
|
||||
contents = contents.replaceAll(oldName, newName);
|
||||
await yamlFile.writeAsString(contents);
|
||||
(yamlFile as File).writeAsStringSync(contents);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
var entry = new File.fromUri(dir.uri.resolve('lib/$oldName.dart'));
|
||||
var entry = File.fromUri(dir.uri.resolve('lib/$oldName.dart'));
|
||||
|
||||
if (await entry.exists()) {
|
||||
await entry.rename(dir.uri.resolve('lib/$newName.dart').toFilePath());
|
||||
print('Renaming library file `${entry.absolute.path}`...');
|
||||
}
|
||||
|
||||
var fmt = new DartFormatter();
|
||||
var fmt = DartFormatter();
|
||||
await for (FileSystemEntity file in dir.list(recursive: true)) {
|
||||
if (file is File && file.path.endsWith('.dart')) {
|
||||
var contents = await file.readAsString();
|
||||
var ast = parseCompilationUnit(contents);
|
||||
var visitor = new RenamingVisitor(oldName, newName)
|
||||
..visitCompilationUnit(ast);
|
||||
|
||||
// TODO: Issue to be fixed: parseCompilationUnit uses Hubbub library which uses discontinued Google front_end library
|
||||
// front_end package. Temporarily commeted out
|
||||
//var ast = parseCompilationUnit(contents);
|
||||
var visitor = RenamingVisitor(oldName, newName);
|
||||
// ..visitCompilationUnit(ast);
|
||||
|
||||
if (visitor.replace.isNotEmpty) {
|
||||
visitor.replace.forEach((range, replacement) {
|
||||
|
|
|
@ -12,7 +12,7 @@ class CustomServiceGenerator extends ServiceGenerator {
|
|||
|
||||
@override
|
||||
void applyToLibrary(LibraryBuilder library, String name, String lower) {
|
||||
library.body.add(new Class((clazz) {
|
||||
library.body.add(Class((clazz) {
|
||||
clazz
|
||||
..name = '${name}Service'
|
||||
..extend = refer('Service');
|
||||
|
|
|
@ -34,7 +34,7 @@ class RethinkServiceGenerator extends ServiceGenerator {
|
|||
void applyToLibrary(LibraryBuilder library, String name, String lower) {
|
||||
library.directives.addAll([
|
||||
'package:angel_rethink/angel_rethink.dart',
|
||||
'package:rethinkdb_driver/rethinkdb_driver.dart'
|
||||
'package:rethinkdb_dart/rethinkdb_dart.dart'
|
||||
].map((str) => new Directive.import(str)));
|
||||
}
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@ import 'dart:math';
|
|||
|
||||
const String _valid =
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
final Random _rnd = new Random.secure();
|
||||
final Random _rnd = Random.secure();
|
||||
|
||||
String randomAlphaNumeric(int length) {
|
||||
var b = new StringBuffer();
|
||||
var b = StringBuffer();
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
b.writeCharCode(_valid.codeUnitAt(_rnd.nextInt(_valid.length)));
|
||||
|
|
|
@ -1,28 +1,27 @@
|
|||
author: Tobe O <thosakwe@gmail.com>
|
||||
#author: Tobe O <thosakwe@gmail.com>
|
||||
description: Command-line tools for the Angel framework, including scaffolding.
|
||||
homepage: https://github.com/angel-dart/angel_cli
|
||||
homepage: https://github.com/dukefirehawk/angel/packages/angel_cli
|
||||
name: angel_cli
|
||||
version: 2.1.7+1
|
||||
version: 3.0.0
|
||||
environment:
|
||||
sdk: ">=2.10.0 <3.0.0"
|
||||
dependencies:
|
||||
analyzer: ">=0.32.0 <2.0.0"
|
||||
args: ^1.0.0
|
||||
analyzer: ^1.1.0
|
||||
args: ^2.0.0
|
||||
code_builder: ^3.0.0
|
||||
dart_style: ^1.0.0
|
||||
glob: ^1.1.0
|
||||
http: ^0.12.0
|
||||
io: ^0.3.2
|
||||
glob: ^2.0.0
|
||||
http: ^0.13.0
|
||||
io: ^0.3.5
|
||||
inflection2: ^0.4.2
|
||||
mustache4dart: ^3.0.0-dev.1.0
|
||||
mustache4dart2: ^0.1.0
|
||||
path: ^1.0.0
|
||||
prompts: ^1.0.0
|
||||
pubspec_parse: ^0.1.2
|
||||
quiver: ^2.0.0
|
||||
recase: ^2.0.0
|
||||
prompts: ^1.3.1
|
||||
pubspec_parse: ^1.0.0
|
||||
quiver: ^3.0.0
|
||||
recase: ^3.0.1
|
||||
shutdown: ^0.4.0
|
||||
watcher: ^0.9.7
|
||||
yaml: ^2.0.0
|
||||
#yamlicious: ^0.0.5
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
watcher: ^1.0.0
|
||||
yaml: ^3.0.0
|
||||
executables:
|
||||
angel: angel
|
||||
|
|
|
@ -64,6 +64,7 @@ abstract class Angel extends http.BaseClient {
|
|||
Stream<String> authenticateViaPopup(String url, {String eventName = 'token'});
|
||||
|
||||
/// Disposes of any outstanding resources.
|
||||
@override
|
||||
Future<void> close();
|
||||
|
||||
/// Applies an [AngelConfigurer] to this instance.
|
||||
|
@ -86,8 +87,8 @@ abstract class Angel extends http.BaseClient {
|
|||
Service<Id, Data> service<Id, Data>(String path,
|
||||
{@deprecated Type type, AngelDeserializer<Data> deserializer});
|
||||
|
||||
@override
|
||||
Future<http.Response> delete(url, {Map<String, String> headers});
|
||||
//@override
|
||||
//Future<http.Response> delete(url, {Map<String, String> headers});
|
||||
|
||||
@override
|
||||
Future<http.Response> get(url, {Map<String, String> headers});
|
||||
|
@ -123,7 +124,7 @@ class AngelAuthResult {
|
|||
|
||||
/// Attempts to deserialize a response from a [Map].
|
||||
factory AngelAuthResult.fromMap(Map data) {
|
||||
final result = new AngelAuthResult();
|
||||
final result = AngelAuthResult();
|
||||
|
||||
if (data is Map && data.containsKey('token') && data['token'] is String)
|
||||
result._token = data['token'].toString();
|
||||
|
@ -132,10 +133,10 @@ class AngelAuthResult {
|
|||
result.data.addAll((data['data'] as Map<String, dynamic>) ?? {});
|
||||
|
||||
if (result.token == null) {
|
||||
throw new FormatException(
|
||||
throw FormatException(
|
||||
'The required "token" field was not present in the given data.');
|
||||
} else if (data['data'] is! Map) {
|
||||
throw new FormatException(
|
||||
throw FormatException(
|
||||
'The required "data" field in the given data was not a map; instead, it was ${data['data']}.');
|
||||
}
|
||||
|
||||
|
@ -144,7 +145,7 @@ class AngelAuthResult {
|
|||
|
||||
/// Attempts to deserialize a response from a [String].
|
||||
factory AngelAuthResult.fromJson(String s) =>
|
||||
new AngelAuthResult.fromMap(json.decode(s) as Map);
|
||||
AngelAuthResult.fromMap(json.decode(s) as Map);
|
||||
|
||||
/// Converts this instance into a JSON-friendly representation.
|
||||
Map<String, dynamic> toJson() {
|
||||
|
@ -199,7 +200,7 @@ abstract class Service<Id, Data> {
|
|||
///
|
||||
/// Handy utility for handling data in a type-safe manner.
|
||||
Service<Id, U> map<U>(U Function(Data) encoder, Data Function(U) decoder) {
|
||||
return new _MappedService(this, encoder, decoder);
|
||||
return _MappedService(this, encoder, decoder);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,7 +215,7 @@ class _MappedService<Id, Data, U> extends Service<Id, U> {
|
|||
Angel get app => inner.app;
|
||||
|
||||
@override
|
||||
Future close() => new Future.value();
|
||||
Future close() => Future.value();
|
||||
|
||||
@override
|
||||
Future<U> create(U data, [Map<String, dynamic> params]) {
|
||||
|
@ -280,19 +281,18 @@ class ServiceList<Id, Data> extends DelegatingList<Data> {
|
|||
|
||||
final Service<Id, Data> service;
|
||||
|
||||
final StreamController<ServiceList<Id, Data>> _onChange =
|
||||
new StreamController();
|
||||
final StreamController<ServiceList<Id, Data>> _onChange = StreamController();
|
||||
|
||||
final List<StreamSubscription> _subs = [];
|
||||
|
||||
ServiceList(this.service, {this.idField = 'id', Equality<Data> equality})
|
||||
: super([]) {
|
||||
_equality = equality;
|
||||
_equality ??= new EqualityBy<Data, Id>((map) {
|
||||
_equality ??= EqualityBy<Data, Id>((map) {
|
||||
if (map is Map)
|
||||
return map[idField ?? 'id'] as Id;
|
||||
else
|
||||
throw new UnsupportedError(
|
||||
throw UnsupportedError(
|
||||
'ServiceList only knows how to find the id from a Map object. Provide a custom `Equality` in your call to the constructor.');
|
||||
});
|
||||
// Index
|
||||
|
|
|
@ -10,14 +10,14 @@ import 'package:http/src/streamed_response.dart' as http;
|
|||
import 'package:path/path.dart' as p;
|
||||
import 'angel_client.dart';
|
||||
|
||||
const Map<String, String> _readHeaders = const {'Accept': 'application/json'};
|
||||
const Map<String, String> _writeHeaders = const {
|
||||
const Map<String, String> _readHeaders = {'Accept': 'application/json'};
|
||||
const Map<String, String> _writeHeaders = {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
};
|
||||
|
||||
Map<String, String> _buildQuery(Map<String, dynamic> params) {
|
||||
return params?.map((k, v) => new MapEntry(k, v.toString()));
|
||||
return params?.map((k, v) => MapEntry(k, v.toString()));
|
||||
}
|
||||
|
||||
bool _invalid(http.Response response) =>
|
||||
|
@ -31,16 +31,16 @@ AngelHttpException failure(http.Response response,
|
|||
var v = json.decode(response.body);
|
||||
|
||||
if (v is Map && (v['is_error'] == true) || v['isError'] == true) {
|
||||
return new AngelHttpException.fromMap(v as Map);
|
||||
return AngelHttpException.fromMap(v as Map);
|
||||
} else {
|
||||
return new AngelHttpException(error,
|
||||
return AngelHttpException(error,
|
||||
message: message ??
|
||||
'Unhandled exception while connecting to Angel backend.',
|
||||
statusCode: response.statusCode,
|
||||
stackTrace: stack);
|
||||
}
|
||||
} catch (e, st) {
|
||||
return new AngelHttpException(error ?? e,
|
||||
return AngelHttpException(error ?? e,
|
||||
message: message ??
|
||||
'Angel backend did not return JSON - an error likely occurred.',
|
||||
statusCode: response.statusCode,
|
||||
|
@ -50,7 +50,7 @@ AngelHttpException failure(http.Response response,
|
|||
|
||||
abstract class BaseAngelClient extends Angel {
|
||||
final StreamController<AngelAuthResult> _onAuthenticated =
|
||||
new StreamController<AngelAuthResult>();
|
||||
StreamController<AngelAuthResult>();
|
||||
final List<Service> _services = [];
|
||||
final http.BaseClient client;
|
||||
|
||||
|
@ -70,7 +70,11 @@ abstract class BaseAngelClient extends Angel {
|
|||
var segments = baseUrl.pathSegments
|
||||
.followedBy(p.split(authEndpoint))
|
||||
.followedBy([type]);
|
||||
var url = baseUrl.replace(path: p.joinAll(segments));
|
||||
|
||||
// TODO: convert windows path to proper url
|
||||
var p1 = p.joinAll(segments).replaceAll('\\', '/');
|
||||
|
||||
var url = baseUrl.replace(path: p1);
|
||||
http.Response response;
|
||||
|
||||
if (credentials != null) {
|
||||
|
@ -85,16 +89,17 @@ abstract class BaseAngelClient extends Angel {
|
|||
}
|
||||
|
||||
try {
|
||||
var v = json.decode(response.body);
|
||||
//var v = json.decode(response.body);
|
||||
var v = jsonDecode(response.body);
|
||||
|
||||
if (v is! Map ||
|
||||
!(v as Map).containsKey('data') ||
|
||||
!(v as Map).containsKey('token')) {
|
||||
throw new AngelHttpException.notAuthenticated(
|
||||
throw AngelHttpException.notAuthenticated(
|
||||
message: "Auth endpoint '$url' did not return a proper response.");
|
||||
}
|
||||
|
||||
var r = new AngelAuthResult.fromMap(v as Map);
|
||||
var r = AngelAuthResult.fromMap(v as Map);
|
||||
_onAuthenticated.add(r);
|
||||
return r;
|
||||
} on AngelHttpException {
|
||||
|
@ -104,6 +109,7 @@ abstract class BaseAngelClient extends Angel {
|
|||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
client.close();
|
||||
await _onAuthenticated.close();
|
||||
|
@ -112,14 +118,16 @@ abstract class BaseAngelClient extends Angel {
|
|||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> logout() async {
|
||||
authToken = null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<http.StreamedResponse> send(http.BaseRequest request) async {
|
||||
if (authToken?.isNotEmpty == true)
|
||||
if (authToken?.isNotEmpty == true) {
|
||||
request.headers['authorization'] ??= 'Bearer $authToken';
|
||||
}
|
||||
return client.send(request);
|
||||
}
|
||||
|
||||
|
@ -128,7 +136,7 @@ abstract class BaseAngelClient extends Angel {
|
|||
String method, url, Map<String, String> headers,
|
||||
[body, Encoding encoding]) async {
|
||||
var request =
|
||||
new http.Request(method, url is Uri ? url : Uri.parse(url.toString()));
|
||||
http.Request(method, url is Uri ? url : Uri.parse(url.toString()));
|
||||
|
||||
if (headers != null) request.headers.addAll(headers);
|
||||
|
||||
|
@ -137,12 +145,12 @@ abstract class BaseAngelClient extends Angel {
|
|||
if (body is String) {
|
||||
request.body = body;
|
||||
} else if (body is List<int>) {
|
||||
request.bodyBytes = new List<int>.from(body);
|
||||
request.bodyBytes = List<int>.from(body);
|
||||
} else if (body is Map<String, dynamic>) {
|
||||
request.bodyFields =
|
||||
body.map((k, v) => MapEntry(k, v is String ? v : v.toString()));
|
||||
} else {
|
||||
throw new ArgumentError.value(body, 'body',
|
||||
throw ArgumentError.value(body, 'body',
|
||||
'must be a String, List<int>, or Map<String, String>.');
|
||||
}
|
||||
}
|
||||
|
@ -154,7 +162,7 @@ abstract class BaseAngelClient extends Angel {
|
|||
Service<Id, Data> service<Id, Data>(String path,
|
||||
{Type type, AngelDeserializer<Data> deserializer}) {
|
||||
var url = baseUrl.replace(path: p.join(baseUrl.path, path));
|
||||
var s = new BaseAngelService<Id, Data>(client, this, url,
|
||||
var s = BaseAngelService<Id, Data>(client, this, url,
|
||||
deserializer: deserializer);
|
||||
_services.add(s);
|
||||
return s;
|
||||
|
@ -166,10 +174,10 @@ abstract class BaseAngelClient extends Angel {
|
|||
return u.replace(path: p.join(baseUrl.path, u.path));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<http.Response> delete(url, {Map<String, String> headers}) async {
|
||||
return sendUnstreamed('DELETE', _join(url), headers);
|
||||
}
|
||||
//@override
|
||||
//Future<http.Response> delete(url, {Map<String, String> headers}) async {
|
||||
// return sendUnstreamed('DELETE', _join(url), headers);
|
||||
//}
|
||||
|
||||
@override
|
||||
Future<http.Response> get(url, {Map<String, String> headers}) async {
|
||||
|
@ -207,12 +215,12 @@ class BaseAngelService<Id, Data> extends Service<Id, Data> {
|
|||
final http.BaseClient client;
|
||||
final AngelDeserializer<Data> deserializer;
|
||||
|
||||
final StreamController<List<Data>> _onIndexed = new StreamController();
|
||||
final StreamController<Data> _onRead = new StreamController(),
|
||||
_onCreated = new StreamController(),
|
||||
_onModified = new StreamController(),
|
||||
_onUpdated = new StreamController(),
|
||||
_onRemoved = new StreamController();
|
||||
final StreamController<List<Data>> _onIndexed = StreamController();
|
||||
final StreamController<Data> _onRead = StreamController(),
|
||||
_onCreated = StreamController(),
|
||||
_onModified = StreamController(),
|
||||
_onUpdated = StreamController(),
|
||||
_onRemoved = StreamController();
|
||||
|
||||
@override
|
||||
Stream<List<Data>> get onIndexed => _onIndexed.stream;
|
||||
|
@ -253,8 +261,9 @@ class BaseAngelService<Id, Data> extends Service<Id, Data> {
|
|||
return deserializer != null ? deserializer(x) : x as Data;
|
||||
}
|
||||
|
||||
makeBody(x) {
|
||||
return json.encode(x);
|
||||
String makeBody(x) {
|
||||
//return json.encode(x);
|
||||
return jsonEncode(x);
|
||||
}
|
||||
|
||||
Future<http.StreamedResponse> send(http.BaseRequest request) {
|
||||
|
@ -272,22 +281,24 @@ class BaseAngelService<Id, Data> extends Service<Id, Data> {
|
|||
|
||||
try {
|
||||
if (_invalid(response)) {
|
||||
if (_onIndexed.hasListener)
|
||||
if (_onIndexed.hasListener) {
|
||||
_onIndexed.addError(failure(response));
|
||||
else
|
||||
} else {
|
||||
throw failure(response);
|
||||
}
|
||||
}
|
||||
|
||||
var v = json.decode(response.body) as List;
|
||||
var r = v.map(deserialize).toList();
|
||||
_onIndexed.add(r);
|
||||
return r;
|
||||
} catch (e, st) {
|
||||
if (_onIndexed.hasListener)
|
||||
if (_onIndexed.hasListener) {
|
||||
_onIndexed.addError(e, st);
|
||||
else
|
||||
} else {
|
||||
throw failure(response, error: e, stack: st);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -13,13 +13,13 @@ export 'angel_client.dart';
|
|||
class Rest extends BaseAngelClient {
|
||||
final List<Service> _services = [];
|
||||
|
||||
Rest(String path) : super(new http.Client() as http.BaseClient, path);
|
||||
Rest(String path) : super(http.Client() as http.BaseClient, path);
|
||||
|
||||
@override
|
||||
Service<Id, Data> service<Id, Data>(String path,
|
||||
{Type type, AngelDeserializer deserializer}) {
|
||||
var url = baseUrl.replace(path: p.join(baseUrl.path, path));
|
||||
var s = new RestService<Id, Data>(client, this, url, type);
|
||||
var s = RestService<Id, Data>(client, this, url, type);
|
||||
_services.add(s);
|
||||
return s;
|
||||
}
|
||||
|
@ -27,10 +27,11 @@ class Rest extends BaseAngelClient {
|
|||
@override
|
||||
Stream<String> authenticateViaPopup(String url,
|
||||
{String eventName = 'token'}) {
|
||||
throw new UnimplementedError(
|
||||
throw UnimplementedError(
|
||||
'Opening popup windows is not supported in the `dart:io` client.');
|
||||
}
|
||||
|
||||
@override
|
||||
Future close() async {
|
||||
await super.close();
|
||||
await Future.wait(_services.map((s) => s.close())).then((_) {
|
||||
|
@ -48,6 +49,7 @@ class RestService<Id, Data> extends BaseAngelService<Id, Data> {
|
|||
|
||||
@override
|
||||
Data deserialize(x) {
|
||||
print(x);
|
||||
if (type != null) {
|
||||
return x.runtimeType == type
|
||||
? x as Data
|
||||
|
@ -58,7 +60,8 @@ class RestService<Id, Data> extends BaseAngelService<Id, Data> {
|
|||
}
|
||||
|
||||
@override
|
||||
makeBody(x) {
|
||||
String makeBody(x) {
|
||||
print(x);
|
||||
if (type != null) {
|
||||
return super.makeBody(god.serializeObject(x));
|
||||
}
|
||||
|
|
|
@ -1,23 +1,41 @@
|
|||
name: angel_client
|
||||
version: 2.0.2
|
||||
version: 3.0.0
|
||||
description: Support for querying Angel servers in the browser, Flutter, and command-line.
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/angel_client
|
||||
publish_to: none
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
sdk: ">=2.10.0 <3.0.0"
|
||||
dependencies:
|
||||
angel_http_exception: ^1.0.0
|
||||
angel_http_exception:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/http_exception
|
||||
collection: ^1.0.0
|
||||
http: ^0.12.0
|
||||
json_god: ">=2.0.0-beta <3.0.0"
|
||||
http: ^0.13.0
|
||||
json_god:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/json_god
|
||||
#dart_json_mapper: ^1.7.0
|
||||
meta: ^1.0.0
|
||||
path: ^1.0.0
|
||||
dev_dependencies:
|
||||
angel_framework: ^2.0.0-alpha
|
||||
angel_model: ^1.0.0
|
||||
angel_framework:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/framework
|
||||
angel_model:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/model
|
||||
async: ^2.0.0
|
||||
build_runner: ^1.0.0
|
||||
build_web_compilers: ^1.0.0
|
||||
build_web_compilers: ^2.12.2
|
||||
mock_request: ^1.0.0
|
||||
pedantic: ^1.0.0
|
||||
test: ^1.0.0
|
||||
pedantic: ^1.11.0
|
||||
test: ^1.16.5
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import 'package:angel_client/angel_client.dart';
|
||||
import 'dart:convert';
|
||||
import 'package:test/test.dart';
|
||||
import 'common.dart';
|
||||
|
||||
main() {
|
||||
var app = new MockAngel();
|
||||
Service todoService = app.service('api/todos');
|
||||
void main() {
|
||||
var app = MockAngel();
|
||||
var todoService = app.service('api/todos');
|
||||
|
||||
test('sets method,body,headers,path', () async {
|
||||
await app.post('/post', headers: {'method': 'post'}, body: 'post');
|
||||
await app.post(Uri.parse('/post'),
|
||||
headers: {'method': 'post'}, body: 'post');
|
||||
expect(app.client.spec.method, 'POST');
|
||||
expect(app.client.spec.path, '/post');
|
||||
expect(app.client.spec.headers['method'], 'post');
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
name: angel_configuration
|
||||
description: Automatic YAML application configuration loader for Angel, with .env support.
|
||||
version: 2.2.0
|
||||
version: 3.0.0
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/angel_configuration
|
||||
publish_to: none
|
||||
environment:
|
||||
sdk: ">=2.0.0 <3.0.0"
|
||||
sdk: ">=2.10.0 <3.0.0"
|
||||
dependencies:
|
||||
angel_framework: ^2.0.0
|
||||
dotenv: ^1.0.0
|
||||
file: ^5.0.0
|
||||
angel_framework:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/framework
|
||||
dotenv: ^3.0.0-nullsafety.0
|
||||
# file: ^5.0.0
|
||||
merge_map: ^1.0.0
|
||||
yaml: ^2.0.0
|
||||
yaml: ^3.1.0
|
||||
dev_dependencies:
|
||||
io: ^0.3.2
|
||||
logging: ^0.11.0
|
||||
io: ^1.0.0
|
||||
# logging: ^0.11.0
|
||||
pedantic: ^1.0.0
|
||||
pretty_logging: ^1.0.0
|
||||
test: ^1.0.0
|
||||
# pretty_logging: ^1.0.0
|
||||
test: ^1.15.7
|
||||
|
|
|
@ -5,11 +5,10 @@ import 'package:angel_configuration/angel_configuration.dart';
|
|||
import 'package:file/local.dart';
|
||||
import 'package:io/ansi.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:pretty_logging/pretty_logging.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
Logger.root.onRecord.listen(prettyLog);
|
||||
//Logger.root.onRecord.listen(prettyLog);
|
||||
|
||||
// Note: Set ANGEL_ENV to 'development'
|
||||
var app = Angel(logger: Logger('angel_configuration'));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:angel_container/angel_container.dart';
|
||||
import '../../angel_container.dart';
|
||||
|
||||
final Map<Symbol, String> _symbolNames = <Symbol, String>{};
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import 'dart:async';
|
||||
import 'dart:mirrors' as dart;
|
||||
import 'package:angel_container/angel_container.dart';
|
||||
import 'package:angel_container/src/reflector.dart';
|
||||
|
||||
import '../exception.dart';
|
||||
import '../reflector.dart';
|
||||
|
||||
/// A [Reflector] implementation that forwards to `dart:mirrors`.
|
||||
///
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:angel_container/angel_container.dart';
|
||||
import '../reflector.dart';
|
||||
|
||||
/// A [Reflector] implementation that performs simple [Map] lookups.
|
||||
///
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:angel_container/angel_container.dart';
|
||||
import 'empty/empty.dart';
|
||||
import 'reflector.dart';
|
||||
|
||||
/// A [Reflector] implementation that throws exceptions on all attempts
|
||||
/// to perform reflection.
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
name: angel_container
|
||||
version: 1.1.0
|
||||
version: 2.0.0
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
description: A hierarchical DI container, and pluggable backends for reflection.
|
||||
homepage: https://github.com/angel-dart/container.git
|
||||
environment:
|
||||
sdk: ">=1.8.0 <3.0.0"
|
||||
sdk: ">=2.10.0 <3.0.0"
|
||||
dependencies:
|
||||
collection: ^1.0.0
|
||||
quiver: ^2.0.0
|
||||
collection: ^1.15.0
|
||||
quiver: ^2.1.5
|
||||
dev_dependencies:
|
||||
pedantic: ^1.0.0
|
||||
test: ^1.0.0
|
||||
pedantic: ^1.11.0
|
||||
test: ^1.16.5
|
|
@ -1,14 +1,19 @@
|
|||
name: angel_container_generator
|
||||
version: 1.0.1
|
||||
version: 2.0.0
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
description: Codegen support for using pkg:reflectable with pkg:angel_container.
|
||||
homepage: https://github.com/angel-dart/container.git
|
||||
publish_to: none
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
sdk: ">=2.10.0 <3.0.0"
|
||||
dependencies:
|
||||
angel_container: ^1.0.0-alpha
|
||||
reflectable: ^2.0.0
|
||||
angel_container:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/container/angel_container
|
||||
reflectable: ^2.2.9
|
||||
dev_dependencies:
|
||||
build_runner: ^1.0.0
|
||||
build_test:
|
||||
test: ^1.0.0
|
||||
build_runner: ^1.11.1
|
||||
build_test: ^1.3.6
|
||||
test: ^1.16.5
|
File diff suppressed because it is too large
Load diff
|
@ -1,14 +1,23 @@
|
|||
author: Tobe O <thosakwe@gmail.com>
|
||||
description: Angel CORS middleware. Port of expressjs/cors to the Angel framework.
|
||||
environment:
|
||||
sdk: ">=2.0.0 <3.0.0"
|
||||
sdk: ">=2.10.0 <3.0.0"
|
||||
homepage: https://github.com/angel-dart/cors.git
|
||||
name: angel_cors
|
||||
version: 2.0.0
|
||||
version: 3.0.0
|
||||
publish_to: none
|
||||
dependencies:
|
||||
angel_framework: ^2.0.0-alpha
|
||||
angel_framework:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/framework
|
||||
dev_dependencies:
|
||||
angel_test: ^2.0.0
|
||||
http: ^0.12.0
|
||||
pedantic: ^1.0.0
|
||||
test: ^1.0.0
|
||||
angel_test:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/test
|
||||
http: ^0.13.0
|
||||
pedantic: ^1.11.0
|
||||
test: ^1.16.5
|
||||
|
|
|
@ -1,16 +1,27 @@
|
|||
name: angel_eventsource
|
||||
version: 1.0.0
|
||||
version: 2.0.0
|
||||
description: Server-sent Events (SSE) plugin for Angel.
|
||||
homepage: https://github.com/angel-dart/eventsource
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
publish_to: none
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
sdk: ">=2.10.0 <3.0.0"
|
||||
dependencies:
|
||||
angel_framework: ^2.0.0-alpha
|
||||
angel_websocket: ^2.0.0-alpha
|
||||
eventsource: ^0.2.0
|
||||
stream_channel: ^1.0.0
|
||||
angel_framework:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/framework
|
||||
angel_websocket:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/websocket
|
||||
eventsource:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/dart-eventsource.git
|
||||
stream_channel: ^2.0.0
|
||||
dev_dependencies:
|
||||
console: ^3.0.0
|
||||
logging:
|
||||
test: ^1.0.0
|
||||
console: ^4.0.0
|
||||
logging: ^1.0.0
|
||||
test: ^1.16.5
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
name: angel_file_service
|
||||
version: 2.0.1
|
||||
version: 3.0.0
|
||||
description: Angel service that persists data to a file on disk.
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/file_service
|
||||
publish_to: none
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
sdk: ">=2.10.0 <3.0.0"
|
||||
dependencies:
|
||||
angel_framework: ^2.0.0-alpha
|
||||
file: ^5.0.0
|
||||
angel_framework:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/framework
|
||||
file: ^6.1.0
|
||||
pool: ^1.0.0
|
||||
dev_dependencies:
|
||||
test: ^1.0.0
|
||||
test: ^1.16.5
|
|
@ -2,7 +2,6 @@ import 'dart:async';
|
|||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_framework/http.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:pretty_logging/pretty_logging.dart';
|
||||
|
||||
Future<void> apiConfigurer(Angel app) async {
|
||||
app.get('/', (req, res) => 'Hello, API!');
|
||||
|
@ -18,7 +17,7 @@ Future<void> frontendConfigurer(Angel app) async {
|
|||
main() async {
|
||||
// Logging set up/boilerplate
|
||||
hierarchicalLoggingEnabled = true;
|
||||
Logger.root.onRecord.listen(prettyLog);
|
||||
//Logger.root.onRecord.listen(prettyLog);
|
||||
|
||||
var app = Angel(logger: Logger('angel'));
|
||||
var http = AngelHttp(app);
|
||||
|
|
|
@ -2,11 +2,10 @@ import 'package:angel_container/mirrors.dart';
|
|||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_framework/http.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:pretty_logging/pretty_logging.dart';
|
||||
|
||||
main() async {
|
||||
// Logging set up/boilerplate
|
||||
Logger.root.onRecord.listen(prettyLog);
|
||||
//Logger.root.onRecord.listen(prettyLog);
|
||||
|
||||
// Create our server.
|
||||
var app = Angel(
|
||||
|
|
|
@ -1,37 +1,55 @@
|
|||
name: angel_framework
|
||||
version: 2.1.1
|
||||
version: 3.0.0
|
||||
description: A high-powered HTTP server with dependency injection, routing and much more.
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/angel_framework
|
||||
publish_to: none
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
sdk: ">=2.10.0 <3.0.0"
|
||||
dependencies:
|
||||
angel_container: ^1.0.4
|
||||
angel_http_exception: ^1.0.0
|
||||
angel_model: ^1.0.0
|
||||
angel_route: ^3.0.0
|
||||
angel_container:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/container/angel_container
|
||||
angel_http_exception:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/http_exception
|
||||
angel_model:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/model
|
||||
angel_route:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/route
|
||||
charcode: ^1.0.0
|
||||
combinator: ^1.0.0
|
||||
file: ^5.0.0
|
||||
http_parser: ^3.0.0
|
||||
file: ^6.1.0
|
||||
http_parser: ^4.0.0
|
||||
http_server: ^0.9.0
|
||||
http2: "^1.0.0"
|
||||
logging: ">=0.11.3 <1.0.0"
|
||||
http2: ^2.0.0
|
||||
logging: ^1.0.0
|
||||
matcher: ^0.12.0
|
||||
merge_map: ^1.0.0
|
||||
meta: ^1.0.0
|
||||
mime: ^0.9.3
|
||||
mime: ^0.9.0
|
||||
mock_request: ^1.0.0
|
||||
path: ^1.0.0
|
||||
# pedantic: ^1.0.0
|
||||
quiver_hashcode: ^2.0.0
|
||||
recase: ^2.0.0
|
||||
recase: ^3.0.1
|
||||
stack_trace: ^1.0.0
|
||||
string_scanner: ^1.0.0
|
||||
tuple: ^1.0.0
|
||||
uuid: ^2.0.0-rc.1
|
||||
tuple: ^1.0.3
|
||||
uuid: ^3.0.1
|
||||
dev_dependencies:
|
||||
http: ^0.12.0
|
||||
io: ^0.3.0
|
||||
pretty_logging: ^1.0.0
|
||||
test: ^1.0.0
|
||||
http: ^0.13.0
|
||||
io: ^1.0.0
|
||||
#pretty_logging: ^1.0.0
|
||||
test: ^1.15.7
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ main() {
|
|||
|
||||
test("middleware", () async {
|
||||
var rgx = RegExp("^Hello, world!");
|
||||
var response = await client.get("$url/todos/0");
|
||||
var response = await client.get(Uri.parse("$url/todos/0"));
|
||||
print('Response: ${response.body}');
|
||||
|
||||
expect(rgx.firstMatch(response.body)?.start, equals(0));
|
||||
|
@ -152,7 +152,7 @@ main() {
|
|||
|
||||
test("controller in group", () async {
|
||||
var rgx = RegExp("^Hello, world!");
|
||||
var response = await client.get("$url/ctrl_group/todos/0");
|
||||
var response = await client.get(Uri.parse("$url/ctrl_group/todos/0"));
|
||||
print('Response: ${response.body}');
|
||||
|
||||
expect(rgx.firstMatch(response.body)?.start, equals(0));
|
||||
|
@ -164,7 +164,7 @@ main() {
|
|||
});
|
||||
|
||||
test("named actions", () async {
|
||||
var response = await client.get("$url/redirect");
|
||||
var response = await client.get(Uri.parse("$url/redirect"));
|
||||
print('Response: ${response.body}');
|
||||
expect(response.body, equals("Hello, \"world!\""));
|
||||
});
|
||||
|
|
|
@ -71,32 +71,33 @@ main() {
|
|||
});
|
||||
|
||||
test("singleton in route", () async {
|
||||
validateTodoSingleton(await client.get("$url/errands"));
|
||||
validateTodoSingleton(await client.get(Uri.parse("$url/errands")));
|
||||
});
|
||||
|
||||
test("singleton in controller", () async {
|
||||
validateTodoSingleton(await client.get("$url/errands2"));
|
||||
validateTodoSingleton(await client.get(Uri.parse("$url/errands2")));
|
||||
});
|
||||
|
||||
test("make in route", () async {
|
||||
var response = await client.get("$url/errands3");
|
||||
var response = await client.get(Uri.parse("$url/errands3"));
|
||||
var text = await json.decode(response.body) as String;
|
||||
expect(text, equals(TEXT));
|
||||
});
|
||||
|
||||
test("make in controller", () async {
|
||||
var response = await client.get("$url/errands4");
|
||||
var response = await client.get(Uri.parse("$url/errands4"));
|
||||
var text = await json.decode(response.body) as String;
|
||||
expect(text, equals(TEXT));
|
||||
});
|
||||
|
||||
test('resolve from future in controller', () async {
|
||||
var response = await client.post('$url/errands4/async', body: 'hey');
|
||||
var response =
|
||||
await client.post(Uri.parse('$url/errands4/async'), body: 'hey');
|
||||
expect(response.body, json.encode({'bar': 'hey'}));
|
||||
});
|
||||
|
||||
test('resolve from future in route', () async {
|
||||
var response = await client.post('$url/async', body: 'yes');
|
||||
var response = await client.post(Uri.parse('$url/async'), body: 'yes');
|
||||
expect(response.body, json.encode({'baz': 'yes'}));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ main() {
|
|||
});
|
||||
|
||||
test("allow override of method", () async {
|
||||
var response = await client
|
||||
.get('$url/foo', headers: {'X-HTTP-Method-Override': 'POST'});
|
||||
var response = await client.get(Uri.parse('$url/foo'),
|
||||
headers: {'X-HTTP-Method-Override': 'POST'});
|
||||
print('Response: ${response.body}');
|
||||
expect(json.decode(response.body), equals({'hello': 'world'}));
|
||||
});
|
||||
|
|
|
@ -59,7 +59,7 @@ main() {
|
|||
count++;
|
||||
});
|
||||
|
||||
var response = await client.get("$url/todos");
|
||||
var response = await client.get(Uri.parse("$url/todos"));
|
||||
print(response.body);
|
||||
expect(count, equals(2));
|
||||
});
|
||||
|
@ -73,7 +73,7 @@ main() {
|
|||
event.cancel({"this_hook": "should never run"});
|
||||
});
|
||||
|
||||
var response = await client.post("$url/todos",
|
||||
var response = await client.post(Uri.parse("$url/todos"),
|
||||
body: json.encode({"arbitrary": "data"}),
|
||||
headers: headers as Map<String, String>);
|
||||
print(response.body);
|
||||
|
@ -93,7 +93,7 @@ main() {
|
|||
event.cancel({"this_hook": "should never run either"});
|
||||
});
|
||||
|
||||
var response = await client.get("$url/todos");
|
||||
var response = await client.get(Uri.parse("$url/todos"));
|
||||
print(response.body);
|
||||
var result = json.decode(response.body) as List;
|
||||
expect(result[0]["angel"], equals("framework"));
|
||||
|
@ -121,7 +121,7 @@ main() {
|
|||
print('Indexing books at path: ${e.request.path}');
|
||||
});
|
||||
|
||||
var response = await client.get('$url/books');
|
||||
var response = await client.get(Uri.parse('$url/books'));
|
||||
print(response.body);
|
||||
|
||||
var result = json.decode(response.body);
|
||||
|
|
|
@ -127,12 +127,12 @@ main() {
|
|||
});
|
||||
|
||||
test('Can match basic url', () async {
|
||||
var response = await client.get("$url/hello");
|
||||
var response = await client.get(Uri.parse("$url/hello"));
|
||||
expect(response.body, equals('"world"'));
|
||||
});
|
||||
|
||||
test('Can match url with multiple parameters', () async {
|
||||
var response = await client.get('$url/name/HELLO/last/WORLD');
|
||||
var response = await client.get(Uri.parse('$url/name/HELLO/last/WORLD'));
|
||||
print('Response: ${response.body}');
|
||||
var json_ = json.decode(response.body);
|
||||
expect(json_, const IsInstanceOf<Map>());
|
||||
|
@ -141,18 +141,18 @@ main() {
|
|||
});
|
||||
|
||||
test('Chained routes', () async {
|
||||
var response = await client.get("$url/chained");
|
||||
var response = await client.get(Uri.parse("$url/chained"));
|
||||
expect(response.body, equals('abc'));
|
||||
});
|
||||
|
||||
test('Can nest another Angel instance', () async {
|
||||
var response = await client.post('$url/nes/ted/foo');
|
||||
var response = await client.post(Uri.parse('$url/nes/ted/foo'));
|
||||
var json_ = json.decode(response.body);
|
||||
expect(json_['route'], equals('foo'));
|
||||
});
|
||||
|
||||
test('Can parse parameters from a nested Angel instance', () async {
|
||||
var response = await client.get('$url/todos/1337/action/test');
|
||||
var response = await client.get(Uri.parse('$url/todos/1337/action/test'));
|
||||
var json_ = json.decode(response.body);
|
||||
print('JSON: $json_');
|
||||
expect(json_['id'], equals('1337'));
|
||||
|
@ -160,27 +160,27 @@ main() {
|
|||
});
|
||||
|
||||
test('Can add and use named middleware', () async {
|
||||
var response = await client.get('$url/intercepted');
|
||||
var response = await client.get(Uri.parse('$url/intercepted'));
|
||||
expect(response.body, equals('Middleware'));
|
||||
});
|
||||
|
||||
test('Middleware via metadata', () async {
|
||||
// Metadata
|
||||
var response = await client.get('$url/meta');
|
||||
var response = await client.get(Uri.parse('$url/meta'));
|
||||
expect(response.body, equals('Middleware'));
|
||||
});
|
||||
|
||||
test('Can serialize function result as JSON', () async {
|
||||
Map headers = <String, String>{'Content-Type': 'application/json'};
|
||||
String postData = json.encode({'it': 'works'});
|
||||
var response = await client.post("$url/lambda",
|
||||
var response = await client.post(Uri.parse("$url/lambda"),
|
||||
headers: headers as Map<String, String>, body: postData);
|
||||
print('Response: ${response.body}');
|
||||
expect(json.decode(response.body)['it'], equals('works'));
|
||||
});
|
||||
|
||||
test('Fallback routes', () async {
|
||||
var response = await client.get('$url/my_favorite_artist');
|
||||
var response = await client.get(Uri.parse('$url/my_favorite_artist'));
|
||||
expect(response.body, equals('"MJ"'));
|
||||
});
|
||||
|
||||
|
@ -193,32 +193,32 @@ main() {
|
|||
});
|
||||
|
||||
test('Redirect to named routes', () async {
|
||||
var response = await client.get('$url/named');
|
||||
var response = await client.get(Uri.parse('$url/named'));
|
||||
print(response.body);
|
||||
expect(json.decode(response.body), equals('Hello tests'));
|
||||
});
|
||||
|
||||
test('Match routes, even with query params', () async {
|
||||
var response =
|
||||
await client.get("$url/log?foo=bar&bar=baz&baz.foo=bar&baz.bar=foo");
|
||||
var response = await client
|
||||
.get(Uri.parse("$url/log?foo=bar&bar=baz&baz.foo=bar&baz.bar=foo"));
|
||||
print(response.body);
|
||||
expect(json.decode(response.body), equals('Logged'));
|
||||
|
||||
response = await client.get("$url/query/foo?bar=baz");
|
||||
response = await client.get(Uri.parse("$url/query/foo?bar=baz"));
|
||||
print(response.body);
|
||||
expect(response.body, equals("Service with Middleware"));
|
||||
});
|
||||
|
||||
test('only match route with matching method', () async {
|
||||
var response = await client.get("$url/method");
|
||||
var response = await client.get(Uri.parse("$url/method"));
|
||||
print(response.body);
|
||||
expect(response.body, '"Only GET"');
|
||||
|
||||
response = await client.post("$url/method");
|
||||
response = await client.post(Uri.parse("$url/method"));
|
||||
print(response.body);
|
||||
expect(response.body, '"Only POST"');
|
||||
|
||||
response = await client.patch("$url/method");
|
||||
response = await client.patch(Uri.parse("$url/method"));
|
||||
print(response.body);
|
||||
expect(response.body, '"MJ"');
|
||||
});
|
||||
|
|
|
@ -35,11 +35,11 @@ main() {
|
|||
});
|
||||
|
||||
test("correct content-type", () async {
|
||||
var response = await client.get('$url/foo');
|
||||
var response = await client.get(Uri.parse('$url/foo'));
|
||||
print('Response: ${response.body}');
|
||||
expect(response.headers['content-type'], contains('application/json'));
|
||||
|
||||
response = await client.get('$url/bar');
|
||||
response = await client.get(Uri.parse('$url/bar'));
|
||||
print('Response: ${response.body}');
|
||||
expect(response.headers['content-type'], contains('text/html'));
|
||||
});
|
||||
|
|
|
@ -44,7 +44,7 @@ main() {
|
|||
|
||||
group('memory', () {
|
||||
test('can index an empty service', () async {
|
||||
var response = await client.get("$url/todos/");
|
||||
var response = await client.get(Uri.parse("$url/todos/"));
|
||||
print(response.body);
|
||||
expect(response.body, equals('[]'));
|
||||
print(response.body);
|
||||
|
@ -53,7 +53,7 @@ main() {
|
|||
|
||||
test('can create data', () async {
|
||||
String postData = json.encode({'text': 'Hello, world!'});
|
||||
var response = await client.post("$url/todos",
|
||||
var response = await client.post(Uri.parse("$url/todos"),
|
||||
headers: headers as Map<String, String>, body: postData);
|
||||
expect(response.statusCode, 201);
|
||||
var jsons = json.decode(response.body);
|
||||
|
@ -63,9 +63,9 @@ main() {
|
|||
|
||||
test('can fetch data', () async {
|
||||
String postData = json.encode({'text': 'Hello, world!'});
|
||||
await client.post("$url/todos",
|
||||
await client.post(Uri.parse("$url/todos"),
|
||||
headers: headers as Map<String, String>, body: postData);
|
||||
var response = await client.get("$url/todos/0");
|
||||
var response = await client.get(Uri.parse("$url/todos/0"));
|
||||
expect(response.statusCode, 200);
|
||||
var jsons = json.decode(response.body);
|
||||
print(jsons);
|
||||
|
@ -74,11 +74,11 @@ main() {
|
|||
|
||||
test('can modify data', () async {
|
||||
String postData = json.encode({'text': 'Hello, world!'});
|
||||
await client.post("$url/todos",
|
||||
await client.post(Uri.parse("$url/todos"),
|
||||
headers: headers as Map<String, String>, body: postData);
|
||||
postData = json.encode({'text': 'modified'});
|
||||
|
||||
var response = await client.patch("$url/todos/0",
|
||||
var response = await client.patch(Uri.parse("$url/todos/0"),
|
||||
headers: headers as Map<String, String>, body: postData);
|
||||
expect(response.statusCode, 200);
|
||||
var jsons = json.decode(response.body);
|
||||
|
@ -88,11 +88,11 @@ main() {
|
|||
|
||||
test('can overwrite data', () async {
|
||||
String postData = json.encode({'text': 'Hello, world!'});
|
||||
await client.post("$url/todos",
|
||||
await client.post(Uri.parse("$url/todos"),
|
||||
headers: headers as Map<String, String>, body: postData);
|
||||
postData = json.encode({'over': 'write'});
|
||||
|
||||
var response = await client.post("$url/todos/0",
|
||||
var response = await client.post(Uri.parse("$url/todos/0"),
|
||||
headers: headers as Map<String, String>, body: postData);
|
||||
expect(response.statusCode, 200);
|
||||
var jsons = json.decode(response.body);
|
||||
|
@ -115,10 +115,11 @@ main() {
|
|||
test('can delete data', () async {
|
||||
String postData = json.encode({'text': 'Hello, world!'});
|
||||
var created = await client
|
||||
.post("$url/todos",
|
||||
.post(Uri.parse("$url/todos"),
|
||||
headers: headers as Map<String, String>, body: postData)
|
||||
.then((r) => json.decode(r.body));
|
||||
var response = await client.delete("$url/todos/${created['id']}");
|
||||
var response =
|
||||
await client.delete(Uri.parse("$url/todos/${created['id']}"));
|
||||
expect(response.statusCode, 200);
|
||||
var json_ = json.decode(response.body);
|
||||
print(json_);
|
||||
|
@ -126,7 +127,7 @@ main() {
|
|||
});
|
||||
|
||||
test('cannot remove all unless explicitly set', () async {
|
||||
var response = await client.delete('$url/todos/null');
|
||||
var response = await client.delete(Uri.parse('$url/todos/null'));
|
||||
expect(response.statusCode, 403);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,19 +4,29 @@ description: The fastest + easiest way to get a GraphQL backend in Dart, using A
|
|||
homepage: https://github.com/angel-dart/graphql
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
sdk: '>=2.10.0 <2.12.0'
|
||||
dependencies:
|
||||
angel_file_service: ^2.0.0
|
||||
angel_framework: ^2.0.0
|
||||
angel_websocket: ^2.0.0
|
||||
angel_validate: ^2.0.0
|
||||
graphql_parser: ^1.0.0
|
||||
graphql_schema: ^1.0.0
|
||||
graphql_server: ^1.0.0
|
||||
angel_file_service: #^2.0.0
|
||||
path: ../../file_service
|
||||
angel_framework: #^2.0.0
|
||||
path: ../../framework
|
||||
angel_websocket: #^2.0.0
|
||||
path: ../../websocket
|
||||
angel_validate: #^2.0.0
|
||||
path: ../../validate
|
||||
graphql_parser: #^1.0.0
|
||||
path: ../graphql_parser
|
||||
graphql_schema: #^1.0.0
|
||||
path: ../graphql_schema
|
||||
graphql_server: #^1.0.0
|
||||
path: ../graphql_server
|
||||
http_parser: ^3.0.0
|
||||
web_socket_channel: ^1.0.0
|
||||
dev_dependencies:
|
||||
angel_serialize: ^2.0.0
|
||||
angel_serialize: #^2.0.0
|
||||
path: ../../serialize/angel_serialize
|
||||
file: ^5.0.0
|
||||
logging: ^0.11.0
|
||||
pedantic: ^1.0.0
|
||||
|
||||
|
|
@ -4,8 +4,9 @@ author: Tobe O <thosakwe@gmail.com>
|
|||
description: Batch and cache database lookups. Works well with GraphQL. Ported from JS.
|
||||
homepage: https://github.com/angel-dart/graphql
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
sdk: '>=2.10.0 <2.12.0'
|
||||
dev_dependencies:
|
||||
graphql_schema: ^1.0.0
|
||||
graphql_schema: #^1.0.0
|
||||
path: ../graphql_schema
|
||||
pedantic: ^1.0.0
|
||||
test: ">=0.12.0 <2.0.0"
|
||||
test: ^1.15.7
|
|
@ -1,14 +1,19 @@
|
|||
name: star_wars
|
||||
publish_to: none
|
||||
environment:
|
||||
sdk: ">=2.10.0 <2.12.0"
|
||||
dependencies:
|
||||
#angel_file_service: ^1.0.0
|
||||
angel_graphql:
|
||||
path: ../angel_graphql
|
||||
angel_hot: ^2.0.0-alpha
|
||||
angel_serialize: ^2.0.0
|
||||
angel_hot: #^2.0.0-alpha
|
||||
path: ../../hot
|
||||
angel_serialize: #^2.0.0
|
||||
path: ../../serialize/angel_serialize
|
||||
io: ^0.3.2
|
||||
dev_dependencies:
|
||||
angel_serialize_generator: ^2.0.0
|
||||
angel_serialize_generator: #^2.0.0
|
||||
path: ../../serialize/angel_serialize_generator
|
||||
build_runner: ^1.0.0
|
||||
graphql_generator:
|
||||
path: ../graphql_generator
|
||||
|
@ -19,3 +24,4 @@ dependency_overrides:
|
|||
path: ../graphql_schema
|
||||
graphql_server:
|
||||
path: ../graphql_server
|
||||
|
|
@ -4,15 +4,18 @@ description: Generates GraphQL schemas from Dart classes, for use with pkg:graph
|
|||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/graphql
|
||||
environment:
|
||||
sdk: ">=2.0.0 <3.0.0"
|
||||
sdk: ">=2.10.0 <2.12.0"
|
||||
dependencies:
|
||||
analyzer: ">=0.27.1 <2.0.0"
|
||||
angel_model: ^1.0.0
|
||||
angel_serialize_generator: ^2.0.0
|
||||
angel_model: #^1.0.0
|
||||
path: ../../model
|
||||
angel_serialize_generator: #^2.0.0
|
||||
path: ../../serialize/angel_serialize_generator
|
||||
build: ^1.0.0
|
||||
build_config: ^0.3.0
|
||||
code_builder: ^3.0.0
|
||||
graphql_schema: ^1.0.2
|
||||
graphql_schema: #^1.0.2
|
||||
path: ../graphql_schema
|
||||
recase: ^2.0.0
|
||||
source_gen: ^0.9.4
|
||||
dev_dependencies:
|
||||
|
|
|
@ -4,7 +4,7 @@ description: Parses GraphQL queries and schemas. Also includes classes for the G
|
|||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/graphql
|
||||
environment:
|
||||
sdk: ">=1.8.0 <3.0.0"
|
||||
sdk: '>=2.10.0 <2.12.0'
|
||||
dependencies:
|
||||
charcode: ^1.0.0
|
||||
source_span: ^1.0.0
|
||||
|
@ -12,4 +12,4 @@ dependencies:
|
|||
dev_dependencies:
|
||||
matcher: any
|
||||
pedantic: ^1.0.0
|
||||
test: ">=0.12.0 <2.0.0"
|
||||
test: ^1.15.7
|
||||
|
|
|
@ -4,10 +4,10 @@ description: An implementation of GraphQL's type system in Dart. Basis of graphq
|
|||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/graphql
|
||||
environment:
|
||||
sdk: ">=1.8.0 <3.0.0"
|
||||
sdk: '>=2.10.0 <2.12.0'
|
||||
dependencies:
|
||||
collection: ^1.0.0
|
||||
meta: ^1.0.0
|
||||
source_span: ^1.0.0
|
||||
dev_dependencies:
|
||||
test: ">=0.12.0 <2.0.0"
|
||||
test: ^1.15.7
|
|
@ -4,19 +4,22 @@ author: Tobe O <thosakwe@gmail.com>
|
|||
description: Base package for implementing GraphQL servers. You might prefer `package:angel_graphql`, the fastest way to implement GraphQL backends in Dart.
|
||||
homepage: https://github.com/angel-dart/graphql
|
||||
environment:
|
||||
sdk: ">=2.0.0 <3.0.0"
|
||||
sdk: ">=2.10.0 <2.12.0"
|
||||
dependencies:
|
||||
angel_serialize: ^2.0.0
|
||||
angel_serialize: #^2.0.0
|
||||
path: ../../serialize/angel_serialize
|
||||
collection: ^1.0.0
|
||||
graphql_schema: ^1.0.0
|
||||
graphql_parser: ^1.0.0
|
||||
graphql_schema: #^1.0.0
|
||||
path: ../graphql_schema
|
||||
graphql_parser: #^1.0.0
|
||||
path: ../graphql_parser
|
||||
meta: ^1.0.0
|
||||
recase: ^2.0.0
|
||||
stream_channel: ^2.0.0
|
||||
tuple: ^1.0.0
|
||||
dev_dependencies:
|
||||
pedantic: ^1.0.0
|
||||
test: ">=0.12.0 <2.0.0"
|
||||
dependency_overrides:
|
||||
graphql_parser:
|
||||
path: ../graphql_parser
|
||||
test: ^1.15.7
|
||||
#dependency_overrides:
|
||||
# graphql_parser:
|
||||
# path: ../graphql_parser
|
||||
|
|
|
@ -9,6 +9,7 @@ import 'package:angel_framework/http.dart';
|
|||
import 'package:angel_websocket/server.dart';
|
||||
import 'package:charcode/ascii.dart';
|
||||
import 'package:glob/glob.dart';
|
||||
import 'package:glob/list_local_fs.dart';
|
||||
import 'package:html_builder/elements.dart';
|
||||
import 'package:html_builder/html_builder.dart';
|
||||
import 'package:io/ansi.dart';
|
||||
|
@ -103,8 +104,9 @@ class HotReloader {
|
|||
response
|
||||
..headers.set(HttpHeaders.contentEncodingHeader, 'gzip')
|
||||
..add(gzip.encode(utf8.encode(_renderer.render(doc))));
|
||||
} else
|
||||
} else {
|
||||
response.write(_renderer.render(doc));
|
||||
}
|
||||
response.close();
|
||||
}
|
||||
|
||||
|
@ -113,11 +115,11 @@ class HotReloader {
|
|||
}
|
||||
|
||||
Future handleRequest(HttpRequest request) async {
|
||||
if (_server != null)
|
||||
if (_server != null) {
|
||||
return await _handle(request);
|
||||
else if (timeout == null)
|
||||
} else if (timeout == null) {
|
||||
_requestQueue.add(request);
|
||||
else {
|
||||
} else {
|
||||
_requestQueue.add(request);
|
||||
Timer(timeout, () {
|
||||
if (_requestQueue.remove(request)) {
|
||||
|
@ -157,9 +159,10 @@ class HotReloader {
|
|||
var isHot = true;
|
||||
_server = await _generateServer();
|
||||
|
||||
if (_paths?.isNotEmpty != true)
|
||||
if (_paths?.isNotEmpty != true) {
|
||||
_logWarning(
|
||||
'You have instantiated a HotReloader without providing any filesystem paths to watch.');
|
||||
}
|
||||
|
||||
bool _sw(String s) {
|
||||
return Platform.executableArguments.any((ss) => ss.startsWith(s));
|
||||
|
@ -173,10 +176,11 @@ class HotReloader {
|
|||
var info = await dev.Service.getInfo();
|
||||
var uri = info.serverUri;
|
||||
uri = uri.replace(path: p.join(uri.path, 'ws'));
|
||||
if (uri.scheme == 'https')
|
||||
if (uri.scheme == 'https') {
|
||||
uri = uri.replace(scheme: 'wss');
|
||||
else
|
||||
} else {
|
||||
uri = uri.replace(scheme: 'ws');
|
||||
}
|
||||
_client = await vm.vmServiceConnectUri(uri.toString());
|
||||
_vmachine ??= await _client.getVM();
|
||||
_mainIsolate ??= _vmachine.isolates.first;
|
||||
|
@ -192,7 +196,9 @@ class HotReloader {
|
|||
//.transform(new _Debounce(new Duration(seconds: 1)))
|
||||
.listen(_handleWatchEvent);
|
||||
|
||||
while (_requestQueue.isNotEmpty) await _handle(_requestQueue.removeFirst());
|
||||
while (_requestQueue.isNotEmpty) {
|
||||
await _handle(_requestQueue.removeFirst());
|
||||
}
|
||||
var server = _io = await HttpServer.bind(address ?? '127.0.0.1', port ?? 0);
|
||||
server.listen(handleRequest);
|
||||
|
||||
|
@ -278,12 +284,14 @@ class HotReloader {
|
|||
} else if (path is Uri) {
|
||||
if (path.scheme == 'package') {
|
||||
var uri = await Isolate.resolvePackageUri(path);
|
||||
if (uri != null)
|
||||
if (uri != null) {
|
||||
await _listenToStat(uri.toFilePath());
|
||||
else
|
||||
} else {
|
||||
await _listenToStat(path.toFilePath());
|
||||
} else
|
||||
}
|
||||
} else {
|
||||
await _listenToStat(path.toFilePath());
|
||||
}
|
||||
} else {
|
||||
throw ArgumentError(
|
||||
'Hot reload paths must be a FileSystemEntity, a Uri, a String or a Glob. You provided: $path');
|
||||
|
@ -305,8 +313,9 @@ class HotReloader {
|
|||
} else if (stat.type == FileSystemEntityType.directory) {
|
||||
var dir = Directory(path);
|
||||
if (!await dir.exists()) return null;
|
||||
} else
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
var watcher = Watcher(path);
|
||||
|
||||
|
@ -357,7 +366,7 @@ class HotReloader {
|
|||
}
|
||||
}
|
||||
|
||||
_handleWatchEvent(WatchEvent e, [bool hot = true]) async {
|
||||
void _handleWatchEvent(WatchEvent e, [bool hot = true]) async {
|
||||
_logInfo('${e.path} changed. Reloading server...\n');
|
||||
await _killServer();
|
||||
_server = null;
|
||||
|
@ -373,7 +382,9 @@ class HotReloader {
|
|||
|
||||
var s = await _generateServer();
|
||||
_server = s;
|
||||
while (_requestQueue.isNotEmpty) await _handle(_requestQueue.removeFirst());
|
||||
while (_requestQueue.isNotEmpty) {
|
||||
await _handle(_requestQueue.removeFirst());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +1,30 @@
|
|||
name: angel_hot
|
||||
description: Supports hot reloading/hot code push of Angel servers on file changes.
|
||||
version: 2.0.6
|
||||
version: 3.0.0
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/hot
|
||||
publish_to: none
|
||||
environment:
|
||||
sdk: ">=2.0.0 <3.0.0"
|
||||
sdk: ">=2.10.0 <3.0.0"
|
||||
dependencies:
|
||||
angel_framework: ^2.0.0-alpha
|
||||
angel_websocket: ^2.0.0-alpha
|
||||
angel_framework:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/framework
|
||||
angel_websocket: #^2.0.0-alpha
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/websocket
|
||||
charcode: ^1.0.0
|
||||
glob: ^1.0.0
|
||||
glob: ^2.0.0
|
||||
html_builder: ^1.0.0
|
||||
io: ^0.3.2
|
||||
io: ^0.3.5
|
||||
path: ^1.0.0
|
||||
vm_service_lib: ^0.3.5
|
||||
watcher: ^0.9.0
|
||||
vm_service_lib: ^3.22.2+1
|
||||
watcher: ^1.0.0
|
||||
dev_dependencies:
|
||||
http: ^0.11.3
|
||||
logging: ^0.11.0
|
||||
http: ^0.13.0
|
||||
logging: ^1.0.0
|
||||
pedantic: ^1.0.0
|
||||
|
|
|
@ -4,13 +4,15 @@ 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
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
sdk: ">=2.10.0 <2.12.0"
|
||||
dependencies:
|
||||
angel_framework: ^2.0.0-alpha
|
||||
angel_framework: #^2.0.0-alpha
|
||||
path: ../framework
|
||||
html_builder: ^1.0.0
|
||||
dev_dependencies:
|
||||
angel_test: ^2.0.0-alpha
|
||||
angel_test: #^2.0.0-alpha
|
||||
path: ../test
|
||||
html: ^0.13.2
|
||||
logging: ^0.11.0
|
||||
test: ^1.0.0
|
||||
test: ^1.15.7
|
||||
pedantic: ^1.0.0
|
|
@ -1,6 +1,7 @@
|
|||
library angel_http_exception;
|
||||
|
||||
import 'package:dart2_constant/convert.dart';
|
||||
//import 'package:dart2_constant/convert.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
/// Exception class that can be serialized to JSON and serialized to clients.
|
||||
/// Carries HTTP-specific metadata, like [statusCode].
|
||||
|
@ -45,11 +46,11 @@ class AngelHttpException implements Exception {
|
|||
|
||||
@override
|
||||
String toString() {
|
||||
return "$statusCode: $message";
|
||||
return '$statusCode: $message';
|
||||
}
|
||||
|
||||
factory AngelHttpException.fromMap(Map data) {
|
||||
return new AngelHttpException(
|
||||
return AngelHttpException(
|
||||
null,
|
||||
statusCode: (data['status_code'] ?? data['statusCode']) as int,
|
||||
message: data['message']?.toString(),
|
||||
|
@ -60,64 +61,64 @@ class AngelHttpException implements Exception {
|
|||
}
|
||||
|
||||
factory AngelHttpException.fromJson(String str) =>
|
||||
new AngelHttpException.fromMap(json.decode(str) as Map);
|
||||
AngelHttpException.fromMap(json.decode(str) as Map);
|
||||
|
||||
/// Throws a 400 Bad Request error, including an optional arrray of (validation?)
|
||||
/// errors you specify.
|
||||
factory AngelHttpException.badRequest(
|
||||
{String message = '400 Bad Request',
|
||||
List<String> errors = const []}) =>
|
||||
new AngelHttpException(null,
|
||||
AngelHttpException(null,
|
||||
message: message, errors: errors, statusCode: 400);
|
||||
|
||||
/// Throws a 401 Not Authenticated error.
|
||||
factory AngelHttpException.notAuthenticated(
|
||||
{String message = '401 Not Authenticated'}) =>
|
||||
new AngelHttpException(null, message: message, statusCode: 401);
|
||||
AngelHttpException(null, message: message, statusCode: 401);
|
||||
|
||||
/// Throws a 402 Payment Required error.
|
||||
factory AngelHttpException.paymentRequired(
|
||||
{String message = '402 Payment Required'}) =>
|
||||
new AngelHttpException(null, message: message, statusCode: 402);
|
||||
AngelHttpException(null, message: message, statusCode: 402);
|
||||
|
||||
/// Throws a 403 Forbidden error.
|
||||
factory AngelHttpException.forbidden({String message = '403 Forbidden'}) =>
|
||||
new AngelHttpException(null, message: message, statusCode: 403);
|
||||
AngelHttpException(null, message: message, statusCode: 403);
|
||||
|
||||
/// Throws a 404 Not Found error.
|
||||
factory AngelHttpException.notFound({String message = '404 Not Found'}) =>
|
||||
new AngelHttpException(null, message: message, statusCode: 404);
|
||||
AngelHttpException(null, message: message, statusCode: 404);
|
||||
|
||||
/// Throws a 405 Method Not Allowed error.
|
||||
factory AngelHttpException.methodNotAllowed(
|
||||
{String message = '405 Method Not Allowed'}) =>
|
||||
new AngelHttpException(null, message: message, statusCode: 405);
|
||||
AngelHttpException(null, message: message, statusCode: 405);
|
||||
|
||||
/// Throws a 406 Not Acceptable error.
|
||||
factory AngelHttpException.notAcceptable(
|
||||
{String message = '406 Not Acceptable'}) =>
|
||||
new AngelHttpException(null, message: message, statusCode: 406);
|
||||
AngelHttpException(null, message: message, statusCode: 406);
|
||||
|
||||
/// Throws a 408 Timeout error.
|
||||
factory AngelHttpException.methodTimeout({String message = '408 Timeout'}) =>
|
||||
new AngelHttpException(null, message: message, statusCode: 408);
|
||||
AngelHttpException(null, message: message, statusCode: 408);
|
||||
|
||||
/// Throws a 409 Conflict error.
|
||||
factory AngelHttpException.conflict({String message = '409 Conflict'}) =>
|
||||
new AngelHttpException(null, message: message, statusCode: 409);
|
||||
AngelHttpException(null, message: message, statusCode: 409);
|
||||
|
||||
/// Throws a 422 Not Processable error.
|
||||
factory AngelHttpException.notProcessable(
|
||||
{String message = '422 Not Processable'}) =>
|
||||
new AngelHttpException(null, message: message, statusCode: 422);
|
||||
AngelHttpException(null, message: message, statusCode: 422);
|
||||
|
||||
/// Throws a 501 Not Implemented error.
|
||||
factory AngelHttpException.notImplemented(
|
||||
{String message = '501 Not Implemented'}) =>
|
||||
new AngelHttpException(null, message: message, statusCode: 501);
|
||||
AngelHttpException(null, message: message, statusCode: 501);
|
||||
|
||||
/// Throws a 503 Unavailable error.
|
||||
factory AngelHttpException.unavailable(
|
||||
{String message = '503 Unavailable'}) =>
|
||||
new AngelHttpException(null, message: message, statusCode: 503);
|
||||
AngelHttpException(null, message: message, statusCode: 503);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
name: angel_http_exception
|
||||
version: 1.1.0
|
||||
version: 2.0.0
|
||||
description: Exception class that can be serialized to JSON and serialized to clients.
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/http_exception
|
||||
#author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/dukefirehawk/angel/packages/http_exception
|
||||
environment:
|
||||
sdk: ">=1.19.0 <3.0.0"
|
||||
dependencies:
|
||||
dart2_constant: ^1.0.0
|
||||
sdk: ">=2.10.0 <3.0.0"
|
||||
dev_dependencies:
|
||||
pedantic: ^1.0.0
|
||||
pedantic: ^1.11.0
|
26
packages/jael/LSP_LICENSE
Normal file
26
packages/jael/LSP_LICENSE
Normal file
|
@ -0,0 +1,26 @@
|
|||
Copyright 2017 dart_language_server authors
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,19 +1,38 @@
|
|||
name: angel_jael
|
||||
version: 2.0.0
|
||||
version: 3.0.0
|
||||
description: Angel support for the Jael templating engine, similar to Blade or Liquid.
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/jael/tree/master/jael
|
||||
publish_to: none
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <=3.0.0"
|
||||
sdk: '>=2.10.0 <3.0.0'
|
||||
dependencies:
|
||||
angel_framework: ^2.0.0-alpha
|
||||
angel_framework:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/framework
|
||||
code_buffer: ^1.0.0
|
||||
file: ^5.0.0
|
||||
jael: ^2.0.0
|
||||
jael_preprocessor: #^2.0.0
|
||||
path: ../jael_preprocessor
|
||||
file: ^6.0.0
|
||||
jael:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/jael/jael
|
||||
jael_preprocessor:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/jael/jael_preprocessor
|
||||
symbol_table: ^2.0.0
|
||||
dev_dependencies:
|
||||
angel_test: ^2.0.0-alpha
|
||||
html:
|
||||
test: ^1.0.0
|
||||
angel_test:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/test
|
||||
html: ^0.15.0
|
||||
test: ^1.15.7
|
||||
dependency_overrides:
|
||||
web_socket_channel: ^2.0.0
|
||||
http: ^0.13.0
|
|
@ -62,7 +62,7 @@ main() {
|
|||
});
|
||||
|
||||
test('can render', () async {
|
||||
var response = await client.get('/github/thosakwe');
|
||||
var response = await client.get(Uri.parse('/github/thosakwe'));
|
||||
print('Body:\n${response.body}');
|
||||
expect(
|
||||
html.parse(response.body).outerHtml,
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
name: jael
|
||||
version: 2.0.2
|
||||
version: 3.0.0
|
||||
description: A simple server-side HTML templating engine for Dart. Comparable to Blade or Liquid.
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://docs.angel-dart.dev/packages/front-end/jael
|
||||
environment:
|
||||
sdk: ">=2.0.0 <3.0.0"
|
||||
sdk: '>=2.10.0 <3.0.0'
|
||||
dependencies:
|
||||
args: ^1.0.0
|
||||
args: ^2.0.0
|
||||
charcode: ^1.0.0
|
||||
code_buffer: ^1.0.0
|
||||
source_span: ^1.0.0
|
||||
|
|
|
@ -3,8 +3,9 @@ import 'dart:io';
|
|||
import 'package:args/args.dart';
|
||||
import 'package:io/ansi.dart';
|
||||
import 'package:io/io.dart';
|
||||
import 'package:dart_language_server/dart_language_server.dart';
|
||||
//import 'package:dart_language_server/dart_language_server.dart';
|
||||
import 'package:jael_language_server/jael_language_server.dart';
|
||||
import 'package:jael_language_server/src/protocol/language_server/server.dart';
|
||||
|
||||
main(List<String> args) async {
|
||||
var argParser = new ArgParser()
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:json_rpc_2/json_rpc_2.dart';
|
||||
|
||||
import 'messages.dart';
|
||||
|
||||
abstract class LanguageServer {
|
||||
final _onDone = Completer<void>();
|
||||
Future<void> get onDone => _onDone.future;
|
||||
|
||||
Future<void> shutdown() async {}
|
||||
void exit() {
|
||||
_onDone.complete();
|
||||
}
|
||||
|
||||
Future<ServerCapabilities> initialize(int clientPid, String rootUri,
|
||||
ClientCapabilities clientCapabilities, String trace) async =>
|
||||
ServerCapabilities((b) => b);
|
||||
void initialized() {}
|
||||
void textDocumentDidOpen(TextDocumentItem document) {}
|
||||
void textDocumentDidChange(VersionedTextDocumentIdentifier documentId,
|
||||
List<TextDocumentContentChangeEvent> changes) {}
|
||||
void textDocumentDidClose(TextDocumentIdentifier documentId) {}
|
||||
Future<CompletionList> textDocumentCompletion(
|
||||
TextDocumentIdentifier documentId, Position position) async =>
|
||||
CompletionList((b) => b);
|
||||
Future<Location> textDocumentDefinition(
|
||||
TextDocumentIdentifier documentId, Position position) async =>
|
||||
null;
|
||||
Future<List<Location>> textDocumentReferences(
|
||||
TextDocumentIdentifier documentId,
|
||||
Position position,
|
||||
ReferenceContext context) async =>
|
||||
[];
|
||||
Future<List<Location>> textDocumentImplementation(
|
||||
TextDocumentIdentifier documentId, Position position) async =>
|
||||
[];
|
||||
Future<List<DocumentHighlight>> textDocumentHighlight(
|
||||
TextDocumentIdentifier documentId, Position position) async =>
|
||||
[];
|
||||
Future<List<SymbolInformation>> textDocumentSymbols(
|
||||
TextDocumentIdentifier documentId) async =>
|
||||
[];
|
||||
Future<List<SymbolInformation>> workspaceSymbol(String query) async => [];
|
||||
Future<dynamic> textDocumentHover(
|
||||
TextDocumentIdentifier documentId, Position position) async =>
|
||||
null;
|
||||
Future<List<dynamic /*Command|CodeAction*/ >> textDocumentCodeAction(
|
||||
TextDocumentIdentifier documentId,
|
||||
Range range,
|
||||
CodeActionContext context) async =>
|
||||
[];
|
||||
Future<void> workspaceExecuteCommand(
|
||||
String command, List<dynamic> arguments) async {}
|
||||
Future<WorkspaceEdit> textDocumentRename(TextDocumentIdentifier documentId,
|
||||
Position position, String newName) async =>
|
||||
null;
|
||||
Stream<Diagnostics> get diagnostics => Stream.empty();
|
||||
Stream<ApplyWorkspaceEditParams> get workspaceEdits => Stream.empty();
|
||||
Stream<ShowMessageParams> get showMessages => Stream.empty();
|
||||
Stream<ShowMessageParams> get logMessages => Stream.empty();
|
||||
|
||||
void setupExtraMethods(Peer peer) {}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,321 @@
|
|||
TextDocumentItem:
|
||||
uri: String
|
||||
text: String
|
||||
languageId: String
|
||||
version: int
|
||||
|
||||
TextDocumentIdentifier:
|
||||
uri: String
|
||||
|
||||
VersionedTextDocumentIdentifier:
|
||||
uri: String
|
||||
version: int
|
||||
|
||||
TextDocumentContentChangeEvent:
|
||||
range: Range
|
||||
rangeLength: int
|
||||
text: String
|
||||
|
||||
Range:
|
||||
start: Position
|
||||
end: Position
|
||||
|
||||
Position:
|
||||
line: int
|
||||
character: int
|
||||
|
||||
Diagnostics:
|
||||
uri: String
|
||||
diagnostics:
|
||||
listType: Diagnostic
|
||||
|
||||
Diagnostic:
|
||||
range: Range
|
||||
severity: int
|
||||
code: dynamic
|
||||
source: String
|
||||
message: String
|
||||
|
||||
CompletionList:
|
||||
isIncomplete: bool
|
||||
items:
|
||||
listType: CompletionItem
|
||||
|
||||
CompletionItem:
|
||||
label: String
|
||||
kind: CompletionItemKind
|
||||
detail: String
|
||||
documentation: String
|
||||
sortText: String
|
||||
filterText: String
|
||||
insertText: String
|
||||
insertTextFormat: InsertTextFormat
|
||||
textEdit: TextEdit
|
||||
additionalTextEdits:
|
||||
listType: TextEdit
|
||||
command: Command
|
||||
data: dynamic
|
||||
|
||||
CompletionItemKind:
|
||||
enumValues:
|
||||
text: 1
|
||||
method: 2
|
||||
function: 3
|
||||
constructor: 4
|
||||
field: 5
|
||||
variable: 6
|
||||
classKind: 7
|
||||
interface: 8
|
||||
module: 9
|
||||
property: 10
|
||||
unit: 11
|
||||
value: 12
|
||||
enumKind: 13
|
||||
keyword: 14
|
||||
snippet: 15
|
||||
color: 16
|
||||
file: 17
|
||||
reference: 18
|
||||
wireType: int
|
||||
|
||||
InsertTextFormat:
|
||||
enumValues:
|
||||
plainText: 1
|
||||
snippet: 2
|
||||
wireType: int
|
||||
|
||||
TextEdit:
|
||||
range: Range
|
||||
newText: String
|
||||
|
||||
Command:
|
||||
title: String
|
||||
command: String
|
||||
arguments:
|
||||
listType: dynamic
|
||||
|
||||
Location:
|
||||
uri: String
|
||||
range: Range
|
||||
|
||||
DynamicRegistrationCapability:
|
||||
dynamicRegistration: bool
|
||||
|
||||
WorkspaceClientCapabilities:
|
||||
applyEdit: bool
|
||||
didChangeConfiguration: DynamicRegistrationCapability
|
||||
didChangeWatchedFiles: DynamicRegistrationCapability
|
||||
symbol: DynamicRegistrationCapability
|
||||
executeCommand: DynamicRegistrationCapability
|
||||
|
||||
SynchronizationCapabilities:
|
||||
dynamicRegistration: bool
|
||||
willSave: bool
|
||||
willSaveWaitUntil: bool
|
||||
didSave: bool
|
||||
|
||||
CompletionItemCapabilities:
|
||||
snippetSupport: bool
|
||||
|
||||
CompletionCapabilities:
|
||||
dynamicRegistration: bool
|
||||
completionItem: CompletionItemCapabilities
|
||||
|
||||
HoverCapabilities:
|
||||
dynamicRegistration: bool
|
||||
contentFormat:
|
||||
listType: String
|
||||
|
||||
CodeActionCapabilities:
|
||||
dynamicRegistration: bool
|
||||
codeActionLiteralSupport: CodeActionLiteralSupport
|
||||
|
||||
CodeActionLiteralSupport:
|
||||
codeActionKind: CodeActionKinds
|
||||
|
||||
CodeActionKinds:
|
||||
valueSet:
|
||||
listType: String # open ended enum
|
||||
|
||||
TextDocumentClientCapabilities:
|
||||
codeAction: CodeActionCapabilities
|
||||
completion: CompletionCapabilities
|
||||
hover: HoverCapabilities
|
||||
synchronization: SynchronizationCapabilities
|
||||
codeLens: DynamicRegistrationCapability
|
||||
definition: DynamicRegistrationCapability
|
||||
documentHighlight: DynamicRegistrationCapability
|
||||
documentLink: DynamicRegistrationCapability
|
||||
documentSymbol: DynamicRegistrationCapability
|
||||
formatting: DynamicRegistrationCapability
|
||||
onTypeFormatting: DynamicRegistrationCapability
|
||||
references: DynamicRegistrationCapability
|
||||
rename: DynamicRegistrationCapability
|
||||
|
||||
ClientCapabilities:
|
||||
workspace: WorkspaceClientCapabilities
|
||||
textDocument: TextDocumentClientCapabilities
|
||||
|
||||
TextDocumentSyncKind:
|
||||
enumValues:
|
||||
none: 0
|
||||
full: 1
|
||||
incremental: 2
|
||||
wireType: int
|
||||
|
||||
CompletionOptions:
|
||||
resolveProvider: bool
|
||||
triggerCharacters:
|
||||
listType: String
|
||||
|
||||
SignatureHelpOptions:
|
||||
triggerCharacters:
|
||||
listType: String
|
||||
|
||||
CodeLensOptions:
|
||||
resolveProvider: bool
|
||||
|
||||
DocumentOnTypeFormattingOptions:
|
||||
firstTriggerCharacter: String
|
||||
moreTriggerCharacter:
|
||||
listType: String
|
||||
|
||||
DocumentLinkOptions:
|
||||
resolveProvider: bool
|
||||
|
||||
ExecuteCommandOptions:
|
||||
commands:
|
||||
listType: String
|
||||
|
||||
SaveOptions:
|
||||
includeText: bool
|
||||
|
||||
TextDocumentSyncOptions:
|
||||
openClose: bool
|
||||
change: TextDocumentSyncKind
|
||||
willSave: bool
|
||||
willSaveWaitUntil: bool
|
||||
save: SaveOptions
|
||||
|
||||
ServerCapabilities:
|
||||
codeActionProvider: bool
|
||||
codeLensProvider: CodeLensOptions
|
||||
completionProvider: CompletionOptions
|
||||
definitionProvider: bool
|
||||
documentFormattingProvider: bool
|
||||
documentHighlightProvider: bool
|
||||
documentLinkProvider: DocumentLinkOptions
|
||||
documentOnTypeFormattingProvider: DocumentOnTypeFormattingOptions
|
||||
documentRangeFormattingProvider: bool
|
||||
documentSymbolProvider: bool
|
||||
executeCommandProvider: ExecuteCommandOptions
|
||||
hoverProvider: bool
|
||||
implementationProvider: bool
|
||||
referencesProvider: bool
|
||||
renameProvider: bool
|
||||
signatureHelpProvider: SignatureHelpOptions
|
||||
textDocumentSync: TextDocumentSyncOptions
|
||||
workspaceSymbolProvider: bool
|
||||
|
||||
ReferenceContext:
|
||||
includeDeclaration: bool
|
||||
|
||||
Hover:
|
||||
contents: String
|
||||
range: Range
|
||||
|
||||
HoverMarkup:
|
||||
contents: MarkupContent
|
||||
range: Range
|
||||
|
||||
CodeActionContext:
|
||||
diagnostics:
|
||||
listType: Diagnostic
|
||||
|
||||
CodeAction:
|
||||
title: String
|
||||
kind: String
|
||||
diagnostics:
|
||||
listType: Diagnostic
|
||||
edit: WorkspaceEdit
|
||||
command: Command
|
||||
|
||||
ApplyWorkspaceEditParams:
|
||||
label: String
|
||||
edit: WorkspaceEdit
|
||||
|
||||
WorkspaceEdit:
|
||||
# Not using `documentChanges` since there is no reasonable way to support text
|
||||
# document version
|
||||
changes:
|
||||
mapType:
|
||||
listType: TextEdit
|
||||
|
||||
DocumentHighlight:
|
||||
range: Range
|
||||
kind: DocumentHighlightKind
|
||||
|
||||
DocumentHighlightKind:
|
||||
enumValues:
|
||||
text: 1
|
||||
read: 2
|
||||
write: 3
|
||||
wireType: int
|
||||
|
||||
SymbolInformation:
|
||||
name: String
|
||||
kind: SymbolKind
|
||||
location: Location
|
||||
containerName: String
|
||||
|
||||
SymbolKind:
|
||||
enumValues:
|
||||
file: 1
|
||||
module: 2
|
||||
namespace: 3
|
||||
package: 4
|
||||
classSymbol: 5
|
||||
method: 6
|
||||
property: 7
|
||||
field: 8
|
||||
constructor: 9
|
||||
enumSymbol: 10
|
||||
interface: 11
|
||||
function: 12
|
||||
variable: 13
|
||||
constant: 14
|
||||
string: 15
|
||||
number: 16
|
||||
boolean: 17
|
||||
array: 18
|
||||
object: 19
|
||||
key: 20
|
||||
nullSymbol: 21
|
||||
enumMember: 22
|
||||
struct: 23
|
||||
event: 24
|
||||
operator: 25
|
||||
typeParameter: 26
|
||||
wireType: int
|
||||
|
||||
MarkupContentKind:
|
||||
enumValues:
|
||||
plaintext: 'plaintext'
|
||||
markdown: 'markdown'
|
||||
wireType: String
|
||||
|
||||
MarkupContent:
|
||||
kind: MarkupContentKind
|
||||
value: String
|
||||
|
||||
MessageType:
|
||||
enumValues:
|
||||
error: 1
|
||||
warning: 2
|
||||
info: 3
|
||||
log: 4
|
||||
wireType: int
|
||||
|
||||
ShowMessageParams:
|
||||
type: MessageType
|
||||
message: String
|
|
@ -0,0 +1,201 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:json_rpc_2/json_rpc_2.dart';
|
||||
|
||||
import 'interface.dart';
|
||||
import 'messages.dart';
|
||||
import 'wireformat.dart';
|
||||
|
||||
/// A Language Server communicating over stdin and stdout.
|
||||
class StdIOLanguageServer {
|
||||
final LanguageServer _server;
|
||||
Future<void> onDone;
|
||||
|
||||
/// Wrap [_server] and register RPC methods using the LSP wire protocol.
|
||||
///
|
||||
/// Methods are guarded against being called before the server is initialized.
|
||||
StdIOLanguageServer.start(this._server) {
|
||||
final peer = Peer(lspChannel(stdin, stdout));
|
||||
|
||||
_lifecycleMethods(peer);
|
||||
_fileHandlingMethods(peer);
|
||||
_notifications(peer);
|
||||
_completionMethods(peer);
|
||||
_referenceMethods(peer);
|
||||
_codeActionMethods(peer);
|
||||
|
||||
_server.setupExtraMethods(peer);
|
||||
|
||||
peer.listen();
|
||||
|
||||
onDone = _server.onDone.then((_) => peer.close()).then((_) => null);
|
||||
}
|
||||
|
||||
bool _isInitialized = false;
|
||||
|
||||
void _lifecycleMethods(Peer peer) {
|
||||
peer
|
||||
..registerMethod('initialize', (params) async {
|
||||
final serverCapabilities = await _server.initialize(
|
||||
params['processId'].valueOr(0) as int,
|
||||
params['rootUri'].valueOr('') as String,
|
||||
ClientCapabilities.fromJson(params['capabilities'].value as Map),
|
||||
params['trace'].valueOr('off') as String);
|
||||
_isInitialized = true;
|
||||
return {'capabilities': serverCapabilities.toJson()};
|
||||
})
|
||||
..registerMethod('initialized', (params) => _server.initialized())
|
||||
..registerMethod('shutdown', _server.shutdown)
|
||||
..registerMethod('exit', _server.exit);
|
||||
}
|
||||
|
||||
/// Register a request that will throw if throw if used before initialization.
|
||||
void _registerRequest(Peer peer, String methodName, Function callback) {
|
||||
peer.registerMethod(methodName, (params) {
|
||||
if (!_isInitialized) {
|
||||
throw RpcException(-32003, 'The server has not been initialized');
|
||||
}
|
||||
return callback(params);
|
||||
});
|
||||
}
|
||||
|
||||
/// Notifications are ignored until after initialization.
|
||||
void _registerNotification(Peer peer, String methodName, Function callback) {
|
||||
peer.registerMethod(methodName, (params) {
|
||||
if (_isInitialized) return callback(params);
|
||||
});
|
||||
}
|
||||
|
||||
void _fileHandlingMethods(Peer peer) {
|
||||
_registerNotification(peer, 'textDocument/didOpen', (params) {
|
||||
_server.textDocumentDidOpen(_documentItem(params));
|
||||
});
|
||||
_registerNotification(peer, 'textDocument/didChange', (params) {
|
||||
_server.textDocumentDidChange(
|
||||
_versionedDocument(params), _contentChanges(params));
|
||||
});
|
||||
_registerNotification(peer, 'textDocument/didClose', (params) {
|
||||
_server.textDocumentDidClose(_document(params));
|
||||
});
|
||||
}
|
||||
|
||||
void _notifications(Peer peer) {
|
||||
_server
|
||||
..diagnostics.map((d) => d.toJson()).forEach((diagnostics) =>
|
||||
peer.sendNotification('textDocument/publishDiagnostics', diagnostics))
|
||||
..workspaceEdits.map((e) => e.toJson()).forEach((edit) {
|
||||
// Ignore response?
|
||||
peer.sendRequest('workspace/applyEdit', edit);
|
||||
})
|
||||
..logMessages.map((e) => e.toJson()).forEach(
|
||||
(message) => peer.sendNotification('window/logMessage', message))
|
||||
..showMessages.map((e) => e.toJson()).forEach(
|
||||
(message) => peer.sendNotification('window/showMessage', message));
|
||||
}
|
||||
|
||||
void _completionMethods(Peer peer) {
|
||||
_registerRequest(
|
||||
peer,
|
||||
'textDocument/completion',
|
||||
(params) => _server
|
||||
.textDocumentCompletion(_document(params), _position(params))
|
||||
.then((r) => r.toJson()));
|
||||
}
|
||||
|
||||
void _referenceMethods(Peer peer) {
|
||||
_registerRequest(
|
||||
peer,
|
||||
'textDocument/definition',
|
||||
(params) => _server
|
||||
.textDocumentDefinition(_document(params), _position(params))
|
||||
.then((r) => r?.toJson()));
|
||||
_registerRequest(
|
||||
peer,
|
||||
'textDocument/hover',
|
||||
(params) => _server
|
||||
.textDocumentHover(_document(params), _position(params))
|
||||
.then((r) => r?.toJson()));
|
||||
_registerRequest(
|
||||
peer,
|
||||
'textDocument/references',
|
||||
(params) => _server
|
||||
.textDocumentReferences(
|
||||
_document(params), _position(params), _referenceContext(params))
|
||||
.then((r) => r?.map((e) => e.toJson())?.toList()));
|
||||
_registerRequest(
|
||||
peer,
|
||||
'textDocument/implementation',
|
||||
(params) => _server
|
||||
.textDocumentImplementation(_document(params), _position(params))
|
||||
.then((r) => r?.map((e) => e.toJson())?.toList()));
|
||||
_registerRequest(
|
||||
peer,
|
||||
'textDocument/documentHighlight',
|
||||
(params) => _server
|
||||
.textDocumentHighlight(_document(params), _position(params))
|
||||
.then((r) => r?.map((e) => e.toJson())?.toList()));
|
||||
_registerRequest(
|
||||
peer,
|
||||
'textDocument/documentSymbol',
|
||||
(params) => _server
|
||||
.textDocumentSymbols(_document(params))
|
||||
.then((r) => r?.map((e) => e.toJson())?.toList()));
|
||||
_registerRequest(
|
||||
peer,
|
||||
'workspace/symbol',
|
||||
(params) => _server
|
||||
.workspaceSymbol(_query(params))
|
||||
.then((r) => r?.map((e) => e.toJson())?.toList()));
|
||||
}
|
||||
|
||||
void _codeActionMethods(Peer peer) {
|
||||
_registerRequest(
|
||||
peer,
|
||||
'textDocument/codeAction',
|
||||
(params) => _server
|
||||
.textDocumentCodeAction(
|
||||
_document(params), _range(params), _codeActionContext(params))
|
||||
.then((r) => r?.map((e) => e.toJson())?.toList()));
|
||||
_registerRequest(
|
||||
peer,
|
||||
'workspace/executeCommand',
|
||||
(params) => _server.workspaceExecuteCommand(
|
||||
params['command'].value as String,
|
||||
params['arguments']?.value as List));
|
||||
_registerRequest(
|
||||
peer,
|
||||
'textDocument/rename',
|
||||
(params) async => (await _server.textDocumentRename(_document(params),
|
||||
_position(params), params['newName'].value as String))
|
||||
.toJson());
|
||||
}
|
||||
}
|
||||
|
||||
TextDocumentItem _documentItem(params) =>
|
||||
TextDocumentItem.fromJson(params['textDocument'].value as Map);
|
||||
|
||||
VersionedTextDocumentIdentifier _versionedDocument(params) =>
|
||||
VersionedTextDocumentIdentifier.fromJson(
|
||||
params['textDocument'].value as Map);
|
||||
|
||||
TextDocumentIdentifier _document(params) =>
|
||||
TextDocumentIdentifier.fromJson(params['textDocument'].value as Map);
|
||||
|
||||
Range _range(params) => Range.fromJson(params['range'].value as Map);
|
||||
|
||||
Position _position(params) =>
|
||||
Position.fromJson(params['position'].value as Map);
|
||||
|
||||
CodeActionContext _codeActionContext(params) =>
|
||||
CodeActionContext.fromJson(params['context'].value as Map);
|
||||
|
||||
ReferenceContext _referenceContext(params) =>
|
||||
ReferenceContext.fromJson(params['context'].value as Map);
|
||||
|
||||
List<TextDocumentContentChangeEvent> _contentChanges(params) =>
|
||||
(params['contentChanges'].value as Iterable)
|
||||
.map((change) => TextDocumentContentChangeEvent.fromJson(change as Map))
|
||||
.toList();
|
||||
|
||||
String _query(params) => params['query'].value as String;
|
|
@ -0,0 +1,98 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:stream_channel/stream_channel.dart';
|
||||
import 'package:async/async.dart';
|
||||
|
||||
StreamChannel<String> lspChannel(
|
||||
Stream<List<int>> stream, StreamSink<List<int>> sink) {
|
||||
final parser = _Parser(stream);
|
||||
final outSink = StreamSinkTransformer.fromHandlers(
|
||||
handleData: _serialize,
|
||||
handleDone: (sink) {
|
||||
sink.close();
|
||||
parser.close();
|
||||
}).bind(sink);
|
||||
return StreamChannel.withGuarantees(parser.stream, outSink);
|
||||
}
|
||||
|
||||
void _serialize(String data, EventSink<List<int>> sink) {
|
||||
final message = utf8.encode(data);
|
||||
final header = 'Content-Length: ${message.length}\r\n\r\n';
|
||||
sink.add(ascii.encode(header));
|
||||
for (var chunk in _chunks(message, 1024)) {
|
||||
sink.add(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
class _Parser {
|
||||
final _streamCtl = StreamController<String>();
|
||||
Stream<String> get stream => _streamCtl.stream;
|
||||
|
||||
final _buffer = <int>[];
|
||||
bool _headerMode = true;
|
||||
int _contentLength = -1;
|
||||
|
||||
StreamSubscription _subscription;
|
||||
|
||||
_Parser(Stream<List<int>> stream) {
|
||||
_subscription =
|
||||
stream.expand((bytes) => bytes).listen(_handleByte, onDone: () {
|
||||
_streamCtl.close();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> close() => _subscription.cancel();
|
||||
|
||||
void _handleByte(int byte) {
|
||||
_buffer.add(byte);
|
||||
if (_headerMode && _headerComplete) {
|
||||
_contentLength = _parseContentLength();
|
||||
_buffer.clear();
|
||||
_headerMode = false;
|
||||
} else if (!_headerMode && _messageComplete) {
|
||||
_streamCtl.add(utf8.decode(_buffer));
|
||||
_buffer.clear();
|
||||
_headerMode = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the entire message is in [_buffer].
|
||||
bool get _messageComplete => _buffer.length >= _contentLength;
|
||||
|
||||
/// Decodes [_buffer] into a String and looks for the 'Content-Length' header.
|
||||
int _parseContentLength() {
|
||||
final asString = ascii.decode(_buffer);
|
||||
final headers = asString.split('\r\n');
|
||||
final lengthHeader =
|
||||
headers.firstWhere((h) => h.startsWith('Content-Length'));
|
||||
final length = lengthHeader.split(':').last.trim();
|
||||
return int.parse(length);
|
||||
}
|
||||
|
||||
/// Whether [_buffer] ends in '\r\n\r\n'.
|
||||
bool get _headerComplete {
|
||||
final l = _buffer.length;
|
||||
return l > 4 &&
|
||||
_buffer[l - 1] == 10 &&
|
||||
_buffer[l - 2] == 13 &&
|
||||
_buffer[l - 3] == 10 &&
|
||||
_buffer[l - 4] == 13;
|
||||
}
|
||||
}
|
||||
|
||||
Iterable<List<T>> _chunks<T>(List<T> data, int chunkSize) sync* {
|
||||
if (data.length <= chunkSize) {
|
||||
yield data;
|
||||
return;
|
||||
}
|
||||
var low = 0;
|
||||
while (low < data.length) {
|
||||
if (data.length > low + chunkSize) {
|
||||
yield data.sublist(low, low + chunkSize);
|
||||
} else {
|
||||
yield data.sublist(low);
|
||||
}
|
||||
low += chunkSize;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import 'dart:async';
|
||||
import 'package:dart_language_server/src/protocol/language_server/interface.dart';
|
||||
import 'package:dart_language_server/src/protocol/language_server/messages.dart';
|
||||
//import 'package:dart_language_server/src/protocol/language_server/interface.dart';
|
||||
//import 'package:dart_language_server/src/protocol/language_server/messages.dart';
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/local.dart';
|
||||
import 'package:file/memory.dart';
|
||||
|
@ -13,6 +13,8 @@ import 'package:string_scanner/string_scanner.dart';
|
|||
import 'package:symbol_table/symbol_table.dart';
|
||||
import 'analyzer.dart';
|
||||
import 'object.dart';
|
||||
import 'protocol/language_server/interface.dart';
|
||||
import 'protocol/language_server/messages.dart';
|
||||
|
||||
class JaelLanguageServer extends LanguageServer {
|
||||
var _diagnostics = new StreamController<Diagnostics>();
|
||||
|
|
|
@ -4,14 +4,16 @@ description: Language Server Protocol implementation for the Jael templating eng
|
|||
author: Tobe Osakwe <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/vscode
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
sdk: '>=2.10.0 <2.12.0'
|
||||
dependencies:
|
||||
args: ^1.0.0
|
||||
dart_language_server: ^0.1.3
|
||||
# dart_language_server: ^0.1.16
|
||||
file: ^5.0.0
|
||||
io: ^0.3.2
|
||||
jael: ^2.0.0
|
||||
jael_preprocessor: ^2.0.0
|
||||
jael: #^2.0.0
|
||||
path: ../jael
|
||||
jael_preprocessor: #^2.0.0
|
||||
path: ../jael_preprocessor
|
||||
json_rpc_2: ^2.0.0
|
||||
logging: ^0.11.3
|
||||
path: ^1.0.0
|
||||
|
@ -20,3 +22,4 @@ dependencies:
|
|||
symbol_table: ^2.0.0
|
||||
executables:
|
||||
jael_language_server: jael_language_server
|
||||
|
|
@ -1,14 +1,19 @@
|
|||
name: jael_preprocessor
|
||||
version: 2.0.1
|
||||
version: 3.0.0
|
||||
description: A pre-processor for resolving blocks and includes within Jael templates.
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/jael/tree/master/jael_preprocessor
|
||||
publish_to: none
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
sdk: '>=2.10.0 <3.0.0'
|
||||
dependencies:
|
||||
file: ^5.0.0
|
||||
jael: ^2.0.0
|
||||
file: ^6.1.0
|
||||
jael:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x
|
||||
path: packages/jael/jael
|
||||
symbol_table: ^2.0.0
|
||||
dev_dependencies:
|
||||
code_buffer:
|
||||
test: ^1.0.0
|
||||
test: ^1.15.7
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
|
@ -206,6 +207,25 @@ class BuildSystemFile extends File {
|
|||
Directory get parent => BuildSystemDirectory(
|
||||
fileSystem, reader, package, fileSystem.path.dirname(path));
|
||||
|
||||
@override
|
||||
Future<Uint8List> readAsBytes() {
|
||||
// TODO: implement readAsBytes
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Uint8List readAsBytesSync() {
|
||||
// TODO: implement readAsBytesSync
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> readAsLines({Encoding encoding = utf8}) {
|
||||
// TODO: implement readAsLines
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
/*
|
||||
@override
|
||||
Future<List<int>> readAsBytes() {
|
||||
var assetId = AssetId(package, path);
|
||||
|
@ -217,7 +237,7 @@ class BuildSystemFile extends File {
|
|||
@override
|
||||
Future<List<String>> readAsLines({Encoding encoding = utf8}) =>
|
||||
throw _unsupported();
|
||||
|
||||
*/
|
||||
@override
|
||||
List<String> readAsLinesSync({Encoding encoding = utf8}) =>
|
||||
throw _unsupported();
|
||||
|
|
|
@ -2,13 +2,15 @@ name: jael_web
|
|||
version: 0.0.0
|
||||
description: Experimental virtual DOM/SPA engine built on Jael. Supports SSR.
|
||||
environment:
|
||||
sdk: ">=2.0.0 <3.0.0"
|
||||
sdk: '>=2.10.0 <2.12.0'
|
||||
dependencies:
|
||||
build: ^1.0.0
|
||||
build_config: ^0.3.0
|
||||
code_builder: ^3.0.0
|
||||
jael: ^2.0.0
|
||||
jael_preprocessor: ^2.0.0
|
||||
jael: #^2.0.0
|
||||
path: ../jael
|
||||
jael_preprocessor: #^2.0.0
|
||||
path: ../jael_preprocessor
|
||||
source_gen: ^0.9.0
|
||||
dev_dependencies:
|
||||
build_runner: ^1.0.0
|
||||
|
|
|
@ -40,7 +40,7 @@ AngelConfigurer jinja({
|
|||
varClose: varClose,
|
||||
commentOpen: commentOpen,
|
||||
commentClose: commentClose,
|
||||
defaultValue: defaultValue,
|
||||
//defaultValue: defaultValue,
|
||||
autoReload: autoReload,
|
||||
filters: filters,
|
||||
tests: tests,
|
||||
|
|
|
@ -4,12 +4,14 @@ version: 1.0.0-rc.0
|
|||
homepage: https://github.com/angel-dart/jinja
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
environment:
|
||||
sdk: '>=2.0.0-dev <3.0.0'
|
||||
sdk: '>=2.10.0 <2.12.0'
|
||||
dependencies:
|
||||
angel_framework: ^2.0.0-alpha
|
||||
angel_framework: #^2.0.0-alpha
|
||||
path: ../framework
|
||||
jinja: ^0.0.4
|
||||
dev_dependencies:
|
||||
angel_test: ^2.0.0
|
||||
angel_test: #^2.0.0
|
||||
path: ../test
|
||||
path: ^1.0.0
|
||||
pedantic: ^1.0.0
|
||||
test: ^1.0.0
|
||||
test: ^1.15.7
|
||||
|
|
84
packages/json_god/.gitignore
vendored
Normal file
84
packages/json_god/.gitignore
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
# See https://www.dartlang.org/tools/private-files.html
|
||||
.idea
|
||||
**/bower_components/
|
||||
|
||||
# Files and directories created by pub
|
||||
.buildlog
|
||||
.packages
|
||||
.project
|
||||
.pub/
|
||||
build/
|
||||
**/packages/
|
||||
|
||||
# Files created by dart2js
|
||||
# (Most Dart developers will use pub build to compile Dart, use/modify these
|
||||
# rules if you intend to use dart2js directly
|
||||
# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
|
||||
# differentiate from explicit Javascript files)
|
||||
# *.dart.js
|
||||
*.part.js
|
||||
*.js.deps
|
||||
# *.js.map
|
||||
*.info.json
|
||||
|
||||
# Directory created by dartdoc
|
||||
doc/
|
||||
|
||||
# Don't commit pubspec lock file
|
||||
# (Library packages only! Remove pattern if developing an application package)
|
||||
pubspec.lock
|
||||
### Dart template
|
||||
# See https://www.dartlang.org/tools/private-files.html
|
||||
|
||||
# Files and directories created by pub
|
||||
|
||||
# Files created by dart2js
|
||||
# (Most Dart developers will use pub build to compile Dart, use/modify these
|
||||
# rules if you intend to use dart2js directly
|
||||
# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
|
||||
# differentiate from explicit Javascript files)
|
||||
*.dart.js
|
||||
# Directory created by dartdoc
|
||||
# Don't commit pubspec lock file
|
||||
# (Library packages only! Remove pattern if developing an application package)
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff:
|
||||
.idea/tasks.xml
|
||||
.idea/dictionaries
|
||||
.idea/jsLibraryMappings.xml
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
.idea/dataSources.ids
|
||||
.idea/dataSources.xml
|
||||
.idea/dataSources.local.xml
|
||||
.idea/sqlDataSources.xml
|
||||
.idea/dynamic.xml
|
||||
.idea/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
.idea/gradle.xml
|
||||
# Mongo Explorer plugin:
|
||||
.idea/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
4
packages/json_god/.travis.yml
Normal file
4
packages/json_god/.travis.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
language: dart
|
||||
dart:
|
||||
- dev
|
||||
- stable
|
8
packages/json_god/CHANGELOG.md
Normal file
8
packages/json_god/CHANGELOG.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
# 2.0.0-beta+3
|
||||
* Long-needed updates, ensured Dart 2 compatibility, fixed DDC breakages.
|
||||
* Patches for reflection bugs with typing.
|
||||
|
||||
# 2.0.0-beta+2
|
||||
* This version breaks in certain Dart versions (likely anything *after* `2.0.0-dev.59.0`)
|
||||
until https://github.com/dart-lang/sdk/issues/33594 is resolved.
|
||||
* Removes the reference to `Schema` class.
|
21
packages/json_god/LICENSE
Normal file
21
packages/json_god/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2016 Tobe O
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
113
packages/json_god/README.md
Normal file
113
packages/json_god/README.md
Normal file
|
@ -0,0 +1,113 @@
|
|||
# JSON God v2
|
||||
|
||||
[![Pub](https://img.shields.io/pub/v/json_god.svg)](https://pub.dartlang.org/packages/json_god)
|
||||
[![build status](https://travis-ci.org/thosakwe/json_god.svg)](https://travis-ci.org/thosakwe/json_god)
|
||||
|
||||
The ***new and improved*** definitive solution for JSON in Dart.
|
||||
|
||||
|
||||
# Installation
|
||||
dependencies:
|
||||
json_god: ^2.0.0-beta
|
||||
|
||||
# Usage
|
||||
|
||||
It is recommended to import the library under an alias, i.e., `god`.
|
||||
|
||||
```dart
|
||||
import 'package:json_god/json_god.dart' as god;
|
||||
```
|
||||
|
||||
## Serializing JSON
|
||||
|
||||
Simply call `god.serialize(x)` to synchronously transform an object into a JSON
|
||||
string.
|
||||
```dart
|
||||
Map map = {"foo": "bar", "numbers": [1, 2, {"three": 4}]};
|
||||
|
||||
// Output: {"foo":"bar","numbers":[1,2,{"three":4]"}
|
||||
String json = god.serialize(map);
|
||||
print(json);
|
||||
```
|
||||
|
||||
You can easily serialize classes, too. JSON God also supports classes as members.
|
||||
```dart
|
||||
class A {
|
||||
String foo;
|
||||
A(this.foo);
|
||||
}
|
||||
|
||||
class B {
|
||||
String hello;
|
||||
A nested;
|
||||
B(String hello, String foo) {
|
||||
this.hello = hello;
|
||||
this.nested = new A(foo);
|
||||
}
|
||||
}
|
||||
|
||||
main() {
|
||||
God god = new God();
|
||||
print(god.serialize(new B("world", "bar")));
|
||||
}
|
||||
|
||||
// Output: {"hello":"world","nested":{"foo":"bar"}}
|
||||
```
|
||||
|
||||
If a class has a `toJson` method, it will be called instead.
|
||||
|
||||
## Deserializing JSON
|
||||
|
||||
Deserialization is equally easy, and is provided through `god.deserialize`.
|
||||
```dart
|
||||
Map map = god.deserialize('{"hello":"world"}');
|
||||
int three = god.deserialize("3");
|
||||
```
|
||||
|
||||
### Deserializing to Classes
|
||||
|
||||
JSON God lets you deserialize JSON into an instance of any type. Simply pass the
|
||||
type as the second argument to `god.deserialize`.
|
||||
|
||||
If the class has a `fromJson` constructor, it will be called instead.
|
||||
|
||||
```dart
|
||||
class Child {
|
||||
String foo;
|
||||
}
|
||||
|
||||
class Parent {
|
||||
String hello;
|
||||
Child child = new Child();
|
||||
}
|
||||
|
||||
main() {
|
||||
God god = new God();
|
||||
Parent parent = god.deserialize('{"hello":"world","child":{"foo":"bar"}}', Parent);
|
||||
print(parent);
|
||||
}
|
||||
```
|
||||
|
||||
**Any JSON-deserializable classes must initializable without parameters.
|
||||
If `new Foo()` would throw an error, then you can't use Foo with JSON.**
|
||||
|
||||
This allows for validation of a sort, as only fields you have declared will be
|
||||
accepted.
|
||||
|
||||
```dart
|
||||
class HasAnInt { int theInt; }
|
||||
|
||||
HasAnInt invalid = god.deserialize('["some invalid input"]', HasAnInt);
|
||||
// Throws an error
|
||||
```
|
||||
|
||||
An exception will be thrown if validation fails.
|
||||
|
||||
# Thank you for using JSON God
|
||||
|
||||
Thank you for using this library. I hope you like it.
|
||||
|
||||
Feel free to follow me on Twitter:
|
||||
[@thosakwe](http://twitter.com/thosakwe)
|
||||
|
||||
Or, check out [my blog](https://thosakwe.com)
|
3
packages/json_god/analysis_options.yaml
Normal file
3
packages/json_god/analysis_options.yaml
Normal file
|
@ -0,0 +1,3 @@
|
|||
analyzer:
|
||||
strong-mode:
|
||||
implicit-casts: false
|
17
packages/json_god/lib/json_god.dart
Normal file
17
packages/json_god/lib/json_god.dart
Normal file
|
@ -0,0 +1,17 @@
|
|||
/// A robust library for JSON serialization and deserialization.
|
||||
library json_god;
|
||||
|
||||
import 'package:dart2_constant/convert.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'src/reflection.dart' as reflection;
|
||||
|
||||
part 'src/serialize.dart';
|
||||
part 'src/deserialize.dart';
|
||||
part 'src/validation.dart';
|
||||
part 'src/util.dart';
|
||||
|
||||
/// Instead, listen to [logger].
|
||||
@deprecated
|
||||
bool debug = false;
|
||||
|
||||
final Logger logger = new Logger('json_god');
|
43
packages/json_god/lib/src/deserialize.dart
Normal file
43
packages/json_god/lib/src/deserialize.dart
Normal file
|
@ -0,0 +1,43 @@
|
|||
part of json_god;
|
||||
|
||||
/// Deserializes a JSON string into a Dart datum.
|
||||
///
|
||||
/// You can also provide an output Type to attempt to serialize the JSON into.
|
||||
deserialize(String json, {Type outputType}) {
|
||||
var deserialized = deserializeJson(json, outputType: outputType);
|
||||
logger.info("Deserialization result: $deserialized");
|
||||
return deserialized;
|
||||
}
|
||||
|
||||
/// Deserializes JSON into data, without validating it.
|
||||
deserializeJson(String s, {Type outputType}) {
|
||||
logger.info("Deserializing the following JSON: $s");
|
||||
|
||||
if (outputType == null) {
|
||||
logger.info("No output type was specified, so we are just using json.decode");
|
||||
return json.decode(s);
|
||||
} else {
|
||||
logger.info("Now deserializing to type: $outputType");
|
||||
return deserializeDatum(json.decode(s), outputType: outputType);
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserializes some JSON-serializable value into a usable Dart value.
|
||||
deserializeDatum(value, {Type outputType}) {
|
||||
if (outputType != null) {
|
||||
return reflection.deserialize(value, outputType, deserializeDatum);
|
||||
} else if (value is List) {
|
||||
logger.info("Deserializing this List: $value");
|
||||
return value.map(deserializeDatum).toList();
|
||||
} else if (value is Map) {
|
||||
logger.info("Deserializing this Map: $value");
|
||||
Map result = {};
|
||||
value.forEach((k, v) {
|
||||
result[k] = deserializeDatum(v);
|
||||
});
|
||||
return result;
|
||||
} else if (_isPrimitive(value)) {
|
||||
logger.info("Value $value is a primitive");
|
||||
return value;
|
||||
}
|
||||
}
|
191
packages/json_god/lib/src/reflection.dart
Normal file
191
packages/json_god/lib/src/reflection.dart
Normal file
|
@ -0,0 +1,191 @@
|
|||
library json_god.reflection;
|
||||
|
||||
import 'dart:mirrors';
|
||||
import 'package:json_god/json_god.dart';
|
||||
|
||||
const Symbol hashCodeSymbol = #hashCode;
|
||||
const Symbol runtimeTypeSymbol = #runtimeType;
|
||||
|
||||
typedef Serializer(value);
|
||||
typedef Deserializer(value, {Type outputType});
|
||||
|
||||
List<Symbol> _findGetters(ClassMirror classMirror) {
|
||||
List<Symbol> result = [];
|
||||
|
||||
classMirror.instanceMembers
|
||||
.forEach((Symbol symbol, MethodMirror methodMirror) {
|
||||
if (methodMirror.isGetter &&
|
||||
symbol != hashCodeSymbol &&
|
||||
symbol != runtimeTypeSymbol) {
|
||||
logger.info("Found getter on instance: $symbol");
|
||||
result.add(symbol);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
serialize(value, Serializer serializer, [@deprecated bool debug = false]) {
|
||||
logger.info("Serializing this value via reflection: $value");
|
||||
Map result = {};
|
||||
InstanceMirror instanceMirror = reflect(value);
|
||||
ClassMirror classMirror = instanceMirror.type;
|
||||
|
||||
// Check for toJson
|
||||
for (Symbol symbol in classMirror.instanceMembers.keys) {
|
||||
if (symbol == #toJson) {
|
||||
logger.info("Running toJson...");
|
||||
var result = instanceMirror.invoke(symbol, []).reflectee;
|
||||
logger.info("Result of serialization via reflection: $result");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
for (Symbol symbol in _findGetters(classMirror)) {
|
||||
String name = MirrorSystem.getName(symbol);
|
||||
var valueForSymbol = instanceMirror.getField(symbol).reflectee;
|
||||
|
||||
try {
|
||||
result[name] = serializer(valueForSymbol);
|
||||
logger.info("Set $name to $valueForSymbol");
|
||||
} catch (e, st) {
|
||||
logger.severe("Could not set $name to $valueForSymbol", e, st);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Result of serialization via reflection: $result");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
deserialize(value, Type outputType, Deserializer deserializer,
|
||||
[@deprecated bool debug = false]) {
|
||||
logger.info("About to deserialize $value to a $outputType");
|
||||
|
||||
try {
|
||||
if (value is List) {
|
||||
List<TypeMirror> typeArguments = reflectType(outputType).typeArguments;
|
||||
|
||||
Iterable it;
|
||||
|
||||
if (typeArguments.isEmpty) {
|
||||
it = value.map(deserializer);
|
||||
} else {
|
||||
it = value.map((item) =>
|
||||
deserializer(item, outputType: typeArguments[0].reflectedType));
|
||||
}
|
||||
|
||||
if (typeArguments.isEmpty) return it.toList();
|
||||
logger.info('Casting list elements to ${typeArguments[0]
|
||||
.reflectedType} via List.from');
|
||||
|
||||
var mirror = reflectType(List, [typeArguments[0].reflectedType]);
|
||||
|
||||
if (mirror is ClassMirror) {
|
||||
var output = mirror.newInstance(#from, [it]).reflectee;
|
||||
logger.info('Casted list type: ${output.runtimeType}');
|
||||
return output;
|
||||
} else {
|
||||
throw new ArgumentError(
|
||||
'${typeArguments[0].reflectedType} is not a class.');
|
||||
}
|
||||
} else if (value is Map)
|
||||
return _deserializeFromJsonByReflection(value, deserializer, outputType);
|
||||
else
|
||||
return deserializer(value);
|
||||
} catch (e, st) {
|
||||
logger.severe('Deserialization failed.', e, st);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Uses mirrors to deserialize an object.
|
||||
_deserializeFromJsonByReflection(
|
||||
data, Deserializer deserializer, Type outputType,
|
||||
[@deprecated bool debug = false]) {
|
||||
// Check for fromJson
|
||||
var typeMirror = reflectType(outputType);
|
||||
|
||||
if (typeMirror is! ClassMirror) {
|
||||
throw new ArgumentError('$outputType is not a class.');
|
||||
}
|
||||
|
||||
var type = typeMirror as ClassMirror;
|
||||
var fromJson =
|
||||
new Symbol('${MirrorSystem.getName(type.simpleName)}.fromJson');
|
||||
|
||||
for (Symbol symbol in type.declarations.keys) {
|
||||
if (symbol == fromJson) {
|
||||
var decl = type.declarations[symbol];
|
||||
|
||||
if (decl is MethodMirror && decl.isConstructor) {
|
||||
logger.info("Running fromJson...");
|
||||
var result = type.newInstance(#fromJson, [data]).reflectee;
|
||||
|
||||
logger.info("Result of deserialization via reflection: $result");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClassMirror classMirror = type;
|
||||
InstanceMirror instanceMirror = classMirror.newInstance(new Symbol(""), []);
|
||||
|
||||
if (classMirror.isSubclassOf(reflectClass(Map))) {
|
||||
var typeArguments = classMirror.typeArguments;
|
||||
|
||||
if (typeArguments.isEmpty ||
|
||||
classMirror.typeArguments
|
||||
.every((t) => t == currentMirrorSystem().dynamicType)) {
|
||||
return data;
|
||||
} else {
|
||||
var mapType =
|
||||
reflectType(Map, typeArguments.map((t) => t.reflectedType).toList())
|
||||
as ClassMirror;
|
||||
logger.info('Casting this map $data to Map of [$typeArguments]');
|
||||
var output = mapType.newInstance(new Symbol(''), []).reflectee;
|
||||
|
||||
for (var key in data.keys) {
|
||||
output[key] = data[key];
|
||||
}
|
||||
|
||||
logger.info('Output: $output of type ${output.runtimeType}');
|
||||
return output;
|
||||
}
|
||||
} else {
|
||||
data.keys.forEach((key) {
|
||||
try {
|
||||
logger.info("Now deserializing value for $key");
|
||||
logger.info("data[\"$key\"] = ${data[key]}");
|
||||
var deserializedValue = deserializer(data[key]);
|
||||
|
||||
logger.info("I want to set $key to the following ${deserializedValue
|
||||
.runtimeType}: $deserializedValue");
|
||||
// Get target type of getter
|
||||
Symbol searchSymbol = new Symbol(key.toString());
|
||||
Symbol symbolForGetter = classMirror.instanceMembers.keys
|
||||
.firstWhere((x) => x == searchSymbol);
|
||||
Type requiredType = classMirror
|
||||
.instanceMembers[symbolForGetter].returnType.reflectedType;
|
||||
if (data[key].runtimeType != requiredType) {
|
||||
logger.info("Currently, $key is a ${data[key].runtimeType}.");
|
||||
logger.info("However, $key must be a $requiredType.");
|
||||
|
||||
deserializedValue =
|
||||
deserializer(deserializedValue, outputType: requiredType);
|
||||
}
|
||||
|
||||
logger.info(
|
||||
"Final deserialized value for $key: $deserializedValue <${deserializedValue
|
||||
.runtimeType}>");
|
||||
instanceMirror.setField(new Symbol(key.toString()), deserializedValue);
|
||||
|
||||
logger.info("Success! $key has been set to $deserializedValue");
|
||||
} catch (e, st) {
|
||||
logger.severe('Could not set value for field $key.', e, st);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return instanceMirror.reflectee;
|
||||
}
|
35
packages/json_god/lib/src/serialize.dart
Normal file
35
packages/json_god/lib/src/serialize.dart
Normal file
|
@ -0,0 +1,35 @@
|
|||
part of json_god;
|
||||
|
||||
/// Serializes any arbitrary Dart datum to JSON. Supports schema validation.
|
||||
String serialize(value) {
|
||||
var serialized = serializeObject(value);
|
||||
logger.info('Serialization result: $serialized');
|
||||
return json.encode(serialized);
|
||||
}
|
||||
|
||||
/// Transforms any Dart datum into a value acceptable to json.encode.
|
||||
serializeObject(value) {
|
||||
if (_isPrimitive(value)) {
|
||||
logger.info("Serializing primitive value: $value");
|
||||
return value;
|
||||
} else if (value is DateTime) {
|
||||
logger.info("Serializing this DateTime: $value");
|
||||
return value.toIso8601String();
|
||||
} else if (value is Iterable) {
|
||||
logger.info("Serializing this Iterable: $value");
|
||||
return value.map(serializeObject).toList();
|
||||
} else if (value is Map) {
|
||||
logger.info("Serializing this Map: $value");
|
||||
return serializeMap(value);
|
||||
} else
|
||||
return serializeObject(reflection.serialize(value, serializeObject));
|
||||
}
|
||||
|
||||
/// Recursively transforms a Map and its children into JSON-serializable data.
|
||||
Map serializeMap(Map value) {
|
||||
Map outputMap = {};
|
||||
value.forEach((key, value) {
|
||||
outputMap[key] = serializeObject(value);
|
||||
});
|
||||
return outputMap;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue