Added pretty_logging and json_serializer
This commit is contained in:
parent
67a81e4442
commit
ee3c10fa53
35 changed files with 1066 additions and 9 deletions
|
@ -1,6 +1,6 @@
|
||||||
# Belatuk Body Parser
|
# Belatuk Body Parser
|
||||||
|
|
||||||
[![version](https://img.shields.io/badge/pub-v3.0.1-brightgreen)](https://pub.dev/packages/belatuk_body_parser)
|
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/belatuk_body_parser?include_prereleases)
|
||||||
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
||||||
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/body_parser/LICENSE)
|
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/body_parser/LICENSE)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Belatuk Code Buffer
|
# Belatuk Code Buffer
|
||||||
|
|
||||||
[![version](https://img.shields.io/badge/pub-v3.0.2-brightgreen)](https://pub.dev/packages/belatuk_code_buffer)
|
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/belatuk_code_buffer?include_prereleases)
|
||||||
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
||||||
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/code_buffer/LICENSE)
|
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/code_buffer/LICENSE)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Belatuk Combinator
|
# Belatuk Combinator
|
||||||
|
|
||||||
[![version](https://img.shields.io/badge/pub-v3.0.1-brightgreen)](https://pub.dev/packages/belatuk_combinator)
|
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/belatuk_combinator?include_prereleases)
|
||||||
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
||||||
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/combinator/LICENSE)
|
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/combinator/LICENSE)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Betaluk Html Builder
|
# Betaluk Html Builder
|
||||||
|
|
||||||
[![version](https://img.shields.io/badge/pub-v3.0.2-brightgreen)](https://pub.dev/packages/belatuk_html_builder)
|
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/belatuk_html_builder?include_prereleases)
|
||||||
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
||||||
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/html_builder/LICENSE)
|
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/html_builder/LICENSE)
|
||||||
|
|
||||||
|
|
4
packages/json_serializer/.travis.yml
Normal file
4
packages/json_serializer/.travis.yml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
language: dart
|
||||||
|
dart:
|
||||||
|
- dev
|
||||||
|
- stable
|
12
packages/json_serializer/AUTHORS.md
Normal file
12
packages/json_serializer/AUTHORS.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Primary Authors
|
||||||
|
===============
|
||||||
|
|
||||||
|
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
||||||
|
|
||||||
|
Thomas is the current maintainer of the code base. He has refactored and migrated the
|
||||||
|
code base to support NNBD.
|
||||||
|
|
||||||
|
* __[Tobe O](thosakwe@gmail.com)__
|
||||||
|
|
||||||
|
Tobe has written much of the original code prior to NNBD migration. He has moved on and
|
||||||
|
is no longer involved with the project.
|
40
packages/json_serializer/CHANGELOG.md
Normal file
40
packages/json_serializer/CHANGELOG.md
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
# Change Log
|
||||||
|
|
||||||
|
## 5.0.0
|
||||||
|
|
||||||
|
* Added `lints` linter
|
||||||
|
* Removed deprecated parameters
|
||||||
|
* Published as `belatuk_json_serializer` package
|
||||||
|
|
||||||
|
## 4.0.3
|
||||||
|
|
||||||
|
* Fixed static analysis errors
|
||||||
|
|
||||||
|
## 4.0.2
|
||||||
|
|
||||||
|
* Updated pubspec description
|
||||||
|
* Fixed static analysis errors
|
||||||
|
|
||||||
|
## 4.0.1
|
||||||
|
|
||||||
|
* Added example
|
||||||
|
* Updated README
|
||||||
|
|
||||||
|
## 4.0.0
|
||||||
|
|
||||||
|
* Migrated to support Dart SDK 2.12.x NNBD
|
||||||
|
|
||||||
|
## 3.0.0
|
||||||
|
|
||||||
|
* Migrated to work with Dart SDK 2.12.x Non NNBD
|
||||||
|
|
||||||
|
## 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.
|
29
packages/json_serializer/LICENSE
Normal file
29
packages/json_serializer/LICENSE
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2021, dukefirehawk.com
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
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.
|
107
packages/json_serializer/README.md
Normal file
107
packages/json_serializer/README.md
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
# Belatuk JSON Serializer
|
||||||
|
|
||||||
|
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/json_serializer?include_prereleases)
|
||||||
|
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
||||||
|
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
|
||||||
|
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/json_serializer/LICENSE)
|
||||||
|
|
||||||
|
**Replacement of `package:json_god` with breaking changes to support NNBD.**
|
||||||
|
|
||||||
|
The ***new and improved*** definitive solution for JSON in Dart. It supports synchronously transform an object into a JSON string and also deserialize a JSON string back into an instance of any type.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
belatuk_json_serializer: ^5.0.0
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
It is recommended to import the library under an alias, i.e., `jsonSerializer`.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
import 'package:belatuk_json_serialization/belatuk_json_serialization.dart' as jsonSerializer;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Serializing JSON
|
||||||
|
|
||||||
|
Simply call `jsonSerializer.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 = jsonSerializer.serialize(map);
|
||||||
|
print(json);
|
||||||
|
```
|
||||||
|
|
||||||
|
You can easily serialize classes, too. Belatuk JSON Serializer also supports classes as members.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
|
||||||
|
class A {
|
||||||
|
String foo;
|
||||||
|
A(this.foo);
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
late String hello;
|
||||||
|
late A nested;
|
||||||
|
B(String hello, String foo) {
|
||||||
|
this.hello = hello;
|
||||||
|
this.nested = A(foo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
print(jsonSerializer.serialize( 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 `jsonSerializer.deserialize`.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
Map map = jsonSerializer.deserialize('{"hello":"world"}');
|
||||||
|
int three = jsonSerializer.deserialize("3");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deserializing to Classes
|
||||||
|
|
||||||
|
Belatuk JSON Serializer lets you deserialize JSON into an instance of any type. Simply pass the type as the second argument to `jsonSerializer.deserialize`.
|
||||||
|
|
||||||
|
If the class has a `fromJson` constructor, it will be called instead.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
class Child {
|
||||||
|
String foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Parent {
|
||||||
|
String hello;
|
||||||
|
Child child = Child();
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
Parent parent = jsonSerializer.deserialize('{"hello":"world","child":{"foo":"bar"}}', Parent);
|
||||||
|
print(parent);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Any JSON-deserializable classes must initializable without parameters. If `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 = jsonSerializer.deserialize('["some invalid input"]', HasAnInt);
|
||||||
|
// Throws an error
|
||||||
|
```
|
||||||
|
|
||||||
|
An exception will be thrown if validation fails.
|
1
packages/json_serializer/analysis_options.yaml
Normal file
1
packages/json_serializer/analysis_options.yaml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
include: package:lints/recommended.yaml
|
18
packages/json_serializer/example/main.dart
Normal file
18
packages/json_serializer/example/main.dart
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import 'package:belatuk_json_serializer/belatuk_json_serializer.dart' as god;
|
||||||
|
|
||||||
|
class A {
|
||||||
|
String foo;
|
||||||
|
A(this.foo);
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
String hello;
|
||||||
|
late A nested;
|
||||||
|
B(this.hello, String foo) {
|
||||||
|
nested = A(foo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
print(god.serialize(B("world", "bar")));
|
||||||
|
}
|
18
packages/json_serializer/lib/belatuk_json_serializer.dart
Normal file
18
packages/json_serializer/lib/belatuk_json_serializer.dart
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/// A robust library for JSON serialization and deserialization.
|
||||||
|
library belatuk_json_serializer;
|
||||||
|
|
||||||
|
//import 'package:dart2_constant/convert.dart';
|
||||||
|
import 'dart:convert';
|
||||||
|
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 = Logger('belatuk_json_serializer');
|
44
packages/json_serializer/lib/src/deserialize.dart
Normal file
44
packages/json_serializer/lib/src/deserialize.dart
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
part of belatuk_json_serializer;
|
||||||
|
|
||||||
|
/// 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;
|
||||||
|
}
|
||||||
|
}
|
188
packages/json_serializer/lib/src/reflection.dart
Normal file
188
packages/json_serializer/lib/src/reflection.dart
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
library belatuk_json_serializer.reflection;
|
||||||
|
|
||||||
|
import 'dart:mirrors';
|
||||||
|
import '../belatuk_json_serializer.dart';
|
||||||
|
|
||||||
|
const Symbol hashCodeSymbol = #hashCode;
|
||||||
|
const Symbol runtimeTypeSymbol = #runtimeType;
|
||||||
|
|
||||||
|
typedef Serializer = dynamic Function(dynamic value);
|
||||||
|
typedef Deserializer = dynamic Function(dynamic 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) {
|
||||||
|
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) {
|
||||||
|
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 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) {
|
||||||
|
// Check for fromJson
|
||||||
|
var typeMirror = reflectType(outputType);
|
||||||
|
|
||||||
|
if (typeMirror is! ClassMirror) {
|
||||||
|
throw ArgumentError('$outputType is not a class.');
|
||||||
|
}
|
||||||
|
|
||||||
|
var type = typeMirror;
|
||||||
|
var fromJson = 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(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(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 = 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(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;
|
||||||
|
}
|
36
packages/json_serializer/lib/src/serialize.dart
Normal file
36
packages/json_serializer/lib/src/serialize.dart
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
part of belatuk_json_serializer;
|
||||||
|
|
||||||
|
/// 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;
|
||||||
|
}
|
5
packages/json_serializer/lib/src/util.dart
Normal file
5
packages/json_serializer/lib/src/util.dart
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
part of belatuk_json_serializer;
|
||||||
|
|
||||||
|
bool _isPrimitive(value) {
|
||||||
|
return value is num || value is bool || value is String || value == null;
|
||||||
|
}
|
25
packages/json_serializer/lib/src/validation.dart
Normal file
25
packages/json_serializer/lib/src/validation.dart
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
part of belatuk_json_serializer;
|
||||||
|
|
||||||
|
/// Thrown when schema validation fails.
|
||||||
|
class JsonValidationError implements Exception {
|
||||||
|
//final Schema schema;
|
||||||
|
final dynamic invalidData;
|
||||||
|
final String cause;
|
||||||
|
|
||||||
|
const JsonValidationError(
|
||||||
|
this.cause, this.invalidData); //, Schema this.schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specifies a schema to validate a class with.
|
||||||
|
class WithSchema {
|
||||||
|
final Map schema;
|
||||||
|
|
||||||
|
const WithSchema(this.schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specifies a schema to validate a class with.
|
||||||
|
class WithSchemaUrl {
|
||||||
|
final String schemaUrl;
|
||||||
|
|
||||||
|
const WithSchemaUrl(this.schemaUrl);
|
||||||
|
}
|
13
packages/json_serializer/pubspec.yaml
Normal file
13
packages/json_serializer/pubspec.yaml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
name: belatuk_json_serializer
|
||||||
|
version: 5.0.0
|
||||||
|
description: Easy JSON to Object serialization and deserialization in Dart.
|
||||||
|
homepage: https://github.com/dart-backend/belatuk-common-utilities/tree/main/packages/json_serializer
|
||||||
|
environment:
|
||||||
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
|
dependencies:
|
||||||
|
#dart2_constant: ^1.0.0
|
||||||
|
logging: ^1.0.1
|
||||||
|
dev_dependencies:
|
||||||
|
stack_trace: ^1.10.0
|
||||||
|
test: ^1.17.4
|
||||||
|
lints: ^1.0.0
|
115
packages/json_serializer/test/deserialization_test.dart
Normal file
115
packages/json_serializer/test/deserialization_test.dart
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
import 'package:belatuk_json_serializer/belatuk_json_serializer.dart' as god;
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
import 'shared.dart';
|
||||||
|
|
||||||
|
main() {
|
||||||
|
god.logger.onRecord.listen(printRecord);
|
||||||
|
|
||||||
|
group('deserialization', () {
|
||||||
|
test('deserialize primitives', testDeserializationOfPrimitives);
|
||||||
|
|
||||||
|
test('deserialize maps', testDeserializationOfMaps);
|
||||||
|
|
||||||
|
test('deserialize maps + reflection',
|
||||||
|
testDeserializationOfMapsWithReflection);
|
||||||
|
|
||||||
|
test('deserialize lists + reflection',
|
||||||
|
testDeserializationOfListsAsWellAsViaReflection);
|
||||||
|
|
||||||
|
test('deserialize with schema validation',
|
||||||
|
testDeserializationWithSchemaValidation);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
testDeserializationOfPrimitives() {
|
||||||
|
expect(god.deserialize('1'), equals(1));
|
||||||
|
expect(god.deserialize('1.4'), equals(1.4));
|
||||||
|
expect(god.deserialize('"Hi!"'), equals("Hi!"));
|
||||||
|
expect(god.deserialize("true"), equals(true));
|
||||||
|
expect(god.deserialize("null"), equals(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
testDeserializationOfMaps() {
|
||||||
|
String simpleJson =
|
||||||
|
'{"hello":"world", "one": 1, "class": {"hello": "world"}}';
|
||||||
|
String nestedJson =
|
||||||
|
'{"foo": {"bar": "baz", "funny": {"how": "life", "seems": 2, "hate": "us sometimes"}}}';
|
||||||
|
var simple = god.deserialize(simpleJson) as Map;
|
||||||
|
var nested = god.deserialize(nestedJson) as Map;
|
||||||
|
|
||||||
|
expect(simple['hello'], equals('world'));
|
||||||
|
expect(simple['one'], equals(1));
|
||||||
|
expect(simple['class']['hello'], equals('world'));
|
||||||
|
|
||||||
|
expect(nested['foo']['bar'], equals('baz'));
|
||||||
|
expect(nested['foo']['funny']['how'], equals('life'));
|
||||||
|
expect(nested['foo']['funny']['seems'], equals(2));
|
||||||
|
expect(nested['foo']['funny']['hate'], equals('us sometimes'));
|
||||||
|
}
|
||||||
|
|
||||||
|
class Pokedex {
|
||||||
|
Map<String, int>? pokemon;
|
||||||
|
}
|
||||||
|
|
||||||
|
testDeserializationOfMapsWithReflection() {
|
||||||
|
var s = '{"pokemon": {"Bulbasaur": 1, "Deoxys": 382}}';
|
||||||
|
var pokedex = god.deserialize(s, outputType: Pokedex) as Pokedex;
|
||||||
|
expect(pokedex.pokemon, hasLength(2));
|
||||||
|
expect(pokedex.pokemon!['Bulbasaur'], 1);
|
||||||
|
expect(pokedex.pokemon!['Deoxys'], 382);
|
||||||
|
}
|
||||||
|
|
||||||
|
testDeserializationOfListsAsWellAsViaReflection() {
|
||||||
|
String json = '''[
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"nested": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hello": "dolly",
|
||||||
|
"nested": [
|
||||||
|
{
|
||||||
|
"bar": "baz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bar": "fight"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
''';
|
||||||
|
|
||||||
|
var list = god.deserialize(json, outputType: (<SampleClass>[]).runtimeType)
|
||||||
|
as List<SampleClass>;
|
||||||
|
SampleClass first = list[0];
|
||||||
|
SampleClass second = list[1];
|
||||||
|
|
||||||
|
expect(list.length, equals(2));
|
||||||
|
expect(first.hello, equals("world"));
|
||||||
|
expect(first.nested.length, equals(0));
|
||||||
|
expect(second.hello, equals("dolly"));
|
||||||
|
expect(second.nested.length, equals(2));
|
||||||
|
|
||||||
|
SampleNestedClass firstNested = second.nested[0];
|
||||||
|
SampleNestedClass secondNested = second.nested[1];
|
||||||
|
|
||||||
|
expect(firstNested.bar, equals("baz"));
|
||||||
|
expect(secondNested.bar, equals("fight"));
|
||||||
|
}
|
||||||
|
|
||||||
|
testDeserializationWithSchemaValidation() async {
|
||||||
|
String babelRcJson =
|
||||||
|
'{"presets":["es2015","stage-0"],"plugins":["add-module-exports"]}';
|
||||||
|
|
||||||
|
var deserialized =
|
||||||
|
god.deserialize(babelRcJson, outputType: BabelRc) as BabelRc;
|
||||||
|
|
||||||
|
print(deserialized.presets.runtimeType);
|
||||||
|
expect(deserialized.presets is List, equals(true));
|
||||||
|
expect(deserialized.presets.length, equals(2));
|
||||||
|
expect(deserialized.presets[0], equals('es2015'));
|
||||||
|
expect(deserialized.presets[1], equals('stage-0'));
|
||||||
|
expect(deserialized.plugins is List, equals(true));
|
||||||
|
expect(deserialized.plugins.length, equals(1));
|
||||||
|
expect(deserialized.plugins[0], equals('add-module-exports'));
|
||||||
|
}
|
133
packages/json_serializer/test/serialization_test.dart
Normal file
133
packages/json_serializer/test/serialization_test.dart
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
//import 'package:dart2_constant/convert.dart';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:belatuk_json_serializer/belatuk_json_serializer.dart' as god;
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
import 'shared.dart';
|
||||||
|
|
||||||
|
main() {
|
||||||
|
god.logger.onRecord.listen(printRecord);
|
||||||
|
|
||||||
|
group('serialization', () {
|
||||||
|
test('serialize primitives', testSerializationOfPrimitives);
|
||||||
|
|
||||||
|
test('serialize dates', testSerializationOfDates);
|
||||||
|
|
||||||
|
test('serialize maps', testSerializationOfMaps);
|
||||||
|
|
||||||
|
test('serialize lists', testSerializationOfLists);
|
||||||
|
|
||||||
|
test('serialize via reflection', testSerializationViaReflection);
|
||||||
|
|
||||||
|
test('serialize with schema validation',
|
||||||
|
testSerializationWithSchemaValidation);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
testSerializationOfPrimitives() {
|
||||||
|
expect(god.serialize(1), equals("1"));
|
||||||
|
expect(god.serialize(1.4), equals("1.4"));
|
||||||
|
expect(god.serialize("Hi!"), equals('"Hi!"'));
|
||||||
|
expect(god.serialize(true), equals("true"));
|
||||||
|
expect(god.serialize(null), equals("null"));
|
||||||
|
}
|
||||||
|
|
||||||
|
testSerializationOfDates() {
|
||||||
|
DateTime date = DateTime.now();
|
||||||
|
String s = god.serialize({'date': date});
|
||||||
|
|
||||||
|
print(s);
|
||||||
|
|
||||||
|
var deserialized = json.decode(s);
|
||||||
|
expect(deserialized['date'], equals(date.toIso8601String()));
|
||||||
|
}
|
||||||
|
|
||||||
|
testSerializationOfMaps() {
|
||||||
|
var simple = json.decode(god
|
||||||
|
.serialize({'hello': 'world', 'one': 1, 'class': SampleClass('world')}));
|
||||||
|
var nested = json.decode(god.serialize({
|
||||||
|
'foo': {
|
||||||
|
'bar': 'baz',
|
||||||
|
'funny': {'how': 'life', 'seems': 2, 'hate': 'us sometimes'}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
expect(simple['hello'], equals('world'));
|
||||||
|
expect(simple['one'], equals(1));
|
||||||
|
expect(simple['class']['hello'], equals('world'));
|
||||||
|
|
||||||
|
expect(nested['foo']['bar'], equals('baz'));
|
||||||
|
expect(nested['foo']['funny']['how'], equals('life'));
|
||||||
|
expect(nested['foo']['funny']['seems'], equals(2));
|
||||||
|
expect(nested['foo']['funny']['hate'], equals('us sometimes'));
|
||||||
|
}
|
||||||
|
|
||||||
|
testSerializationOfLists() {
|
||||||
|
List pandorasBox = [
|
||||||
|
1,
|
||||||
|
"2",
|
||||||
|
{"num": 3, "four": SampleClass('five')},
|
||||||
|
SampleClass('six')..nested.add(SampleNestedClass('seven'))
|
||||||
|
];
|
||||||
|
String s = god.serialize(pandorasBox);
|
||||||
|
print(s);
|
||||||
|
|
||||||
|
var deserialized = json.decode(s);
|
||||||
|
|
||||||
|
expect(deserialized is List, equals(true));
|
||||||
|
expect(deserialized.length, equals(4));
|
||||||
|
expect(deserialized[0], equals(1));
|
||||||
|
expect(deserialized[1], equals("2"));
|
||||||
|
expect(deserialized[2] is Map, equals(true));
|
||||||
|
expect(deserialized[2]['num'], equals(3));
|
||||||
|
expect(deserialized[2]['four'] is Map, equals(true));
|
||||||
|
expect(deserialized[2]['four']['hello'], equals('five'));
|
||||||
|
expect(deserialized[3] is Map, equals(true));
|
||||||
|
expect(deserialized[3]['hello'], equals('six'));
|
||||||
|
expect(deserialized[3]['nested'] is List, equals(true));
|
||||||
|
expect(deserialized[3]['nested'].length, equals(1));
|
||||||
|
expect(deserialized[3]['nested'][0] is Map, equals(true));
|
||||||
|
expect(deserialized[3]['nested'][0]['bar'], equals('seven'));
|
||||||
|
}
|
||||||
|
|
||||||
|
testSerializationViaReflection() {
|
||||||
|
SampleClass sample = SampleClass('world');
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
sample.nested.add(SampleNestedClass('baz'));
|
||||||
|
}
|
||||||
|
|
||||||
|
String s = god.serialize(sample);
|
||||||
|
print(s);
|
||||||
|
|
||||||
|
var deserialized = json.decode(s);
|
||||||
|
expect(deserialized['hello'], equals('world'));
|
||||||
|
expect(deserialized['nested'] is List, equals(true));
|
||||||
|
expect(deserialized['nested'].length == 3, equals(true));
|
||||||
|
expect(deserialized['nested'][0]['bar'], equals('baz'));
|
||||||
|
expect(deserialized['nested'][1]['bar'], equals('baz'));
|
||||||
|
expect(deserialized['nested'][2]['bar'], equals('baz'));
|
||||||
|
}
|
||||||
|
|
||||||
|
testSerializationWithSchemaValidation() async {
|
||||||
|
BabelRc babelRc =
|
||||||
|
BabelRc(presets: ['es2015', 'stage-0'], plugins: ['add-module-exports']);
|
||||||
|
|
||||||
|
String s = god.serialize(babelRc);
|
||||||
|
print(s);
|
||||||
|
|
||||||
|
var deserialized = json.decode(s);
|
||||||
|
|
||||||
|
expect(deserialized['presets'] is List, equals(true));
|
||||||
|
expect(deserialized['presets'].length, equals(2));
|
||||||
|
expect(deserialized['presets'][0], equals('es2015'));
|
||||||
|
expect(deserialized['presets'][1], equals('stage-0'));
|
||||||
|
expect(deserialized['plugins'] is List, equals(true));
|
||||||
|
expect(deserialized['plugins'].length, equals(1));
|
||||||
|
expect(deserialized['plugins'][0], equals('add-module-exports'));
|
||||||
|
|
||||||
|
//Map babelRc2 = {'presets': 'Hello, world!'};
|
||||||
|
|
||||||
|
String json2 = god.serialize(babelRc);
|
||||||
|
print(json2);
|
||||||
|
}
|
51
packages/json_serializer/test/shared.dart
Normal file
51
packages/json_serializer/test/shared.dart
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:belatuk_json_serializer/belatuk_json_serializer.dart';
|
||||||
|
import 'package:stack_trace/stack_trace.dart';
|
||||||
|
|
||||||
|
void printRecord(LogRecord rec) {
|
||||||
|
print(rec);
|
||||||
|
if (rec.error != null) print(rec.error);
|
||||||
|
if (rec.stackTrace != null) print(Chain.forTrace(rec.stackTrace!).terse);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SampleNestedClass {
|
||||||
|
String? bar;
|
||||||
|
|
||||||
|
SampleNestedClass([String? this.bar]);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SampleClass {
|
||||||
|
String? hello;
|
||||||
|
List<SampleNestedClass> nested = [];
|
||||||
|
|
||||||
|
SampleClass([String? this.hello]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@WithSchemaUrl(
|
||||||
|
"http://raw.githubusercontent.com/SchemaStore/schemastore/master/src/schemas/json/babelrc.json")
|
||||||
|
class BabelRc {
|
||||||
|
List<String> presets;
|
||||||
|
List<String> plugins;
|
||||||
|
|
||||||
|
BabelRc(
|
||||||
|
{List<String> this.presets: const [],
|
||||||
|
List<String> this.plugins: const []});
|
||||||
|
}
|
||||||
|
|
||||||
|
@WithSchema(const {
|
||||||
|
r"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"title": "Validated Sample Class",
|
||||||
|
"description": "Sample schema for validation via JSON God",
|
||||||
|
"type": "object",
|
||||||
|
"hello": const {"description": "A friendly greeting.", "type": "string"},
|
||||||
|
"nested": const {
|
||||||
|
"description": "A list of NestedSampleClass items within this instance.",
|
||||||
|
"type": "array",
|
||||||
|
"items": const {
|
||||||
|
"type": "object",
|
||||||
|
"bar": const {"description": "Filler text", "type": "string"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": const ["hello", "nested"]
|
||||||
|
})
|
||||||
|
class ValidatedSampleClass {}
|
32
packages/json_serializer/test/to_json_test.dart
Normal file
32
packages/json_serializer/test/to_json_test.dart
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import 'package:belatuk_json_serializer/belatuk_json_serializer.dart' as god;
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
import 'shared.dart';
|
||||||
|
|
||||||
|
main() {
|
||||||
|
god.logger.onRecord.listen(printRecord);
|
||||||
|
|
||||||
|
test('fromJson', () {
|
||||||
|
var foo = god.deserialize('{"bar":"baz"}', outputType: Foo) as Foo;
|
||||||
|
|
||||||
|
expect(foo is Foo, true);
|
||||||
|
expect(foo.text, equals('baz'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('toJson', () {
|
||||||
|
var foo = Foo(text: 'baz');
|
||||||
|
var data = god.serializeObject(foo);
|
||||||
|
expect(data, equals({'bar': 'baz', 'foo': 'poobaz'}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
String? text;
|
||||||
|
|
||||||
|
String get foo => 'poo$text';
|
||||||
|
|
||||||
|
Foo({this.text});
|
||||||
|
|
||||||
|
factory Foo.fromJson(Map json) => Foo(text: json['bar'].toString());
|
||||||
|
|
||||||
|
Map toJson() => {'bar': text, 'foo': foo};
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
# Belatuk Merge Map
|
# Belatuk Merge Map
|
||||||
|
|
||||||
[![version](https://img.shields.io/badge/pub-v3.0.2-brightgreen)](https://pub.dev/packages/belatuk_merge_map)
|
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/belatuk_merge_map?include_prereleases)
|
||||||
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
||||||
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/merge_map/LICENSE)
|
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/merge_map/LICENSE)
|
||||||
|
|
||||||
|
|
12
packages/pretty_logging/AUTHORS.md
Normal file
12
packages/pretty_logging/AUTHORS.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Primary Authors
|
||||||
|
===============
|
||||||
|
|
||||||
|
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
||||||
|
|
||||||
|
Thomas is the current maintainer of the code base. He has refactored and migrated the
|
||||||
|
code base to support NNBD.
|
||||||
|
|
||||||
|
* __[Tobe O](thosakwe@gmail.com)__
|
||||||
|
|
||||||
|
Tobe has written much of the original code prior to NNBD migration. He has moved on and
|
||||||
|
is no longer involved with the project.
|
31
packages/pretty_logging/CHANGELOG.md
Normal file
31
packages/pretty_logging/CHANGELOG.md
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# Change Log
|
||||||
|
|
||||||
|
## 4.0.0
|
||||||
|
|
||||||
|
* Added `lints` linter
|
||||||
|
* Removed deprecated parameters
|
||||||
|
* Published as `belatuk_pretty_logging` package
|
||||||
|
|
||||||
|
## 3.0.3
|
||||||
|
|
||||||
|
* Updated README
|
||||||
|
|
||||||
|
## 3.0.2
|
||||||
|
|
||||||
|
* Updated README
|
||||||
|
|
||||||
|
## 3.0.1
|
||||||
|
|
||||||
|
* Fixed invalid homepage url in pubspec.yaml
|
||||||
|
|
||||||
|
## 3.0.0
|
||||||
|
|
||||||
|
* Migrated to support Dart SDK 2.12.x NNBD
|
||||||
|
|
||||||
|
## 2.0.0
|
||||||
|
|
||||||
|
* Migrated to work with Dart SDK 2.12.x Non NNBD
|
||||||
|
|
||||||
|
## 1.0.0
|
||||||
|
|
||||||
|
* Initial release.
|
29
packages/pretty_logging/LICENSE
Normal file
29
packages/pretty_logging/LICENSE
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2021, dukefirehawk.com
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
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.
|
41
packages/pretty_logging/README.md
Normal file
41
packages/pretty_logging/README.md
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
# Belatuk Petty Logging
|
||||||
|
|
||||||
|
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/belatuk_pretty_logging?include_prereleases)
|
||||||
|
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
||||||
|
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
|
||||||
|
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/pretty_logging/LICENSE)
|
||||||
|
|
||||||
|
**Replacement of `package:pretty_logging` with breaking changes to support NNBD.**
|
||||||
|
|
||||||
|
Standalone helper for colorful logging output, using pkg:io AnsiCode.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
In your `pubspec.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
dependencies:
|
||||||
|
belatuk_pretty_logging: ^4.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Basic usage is very simple:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
myLogger.onRecord.listen(prettyLog);
|
||||||
|
```
|
||||||
|
|
||||||
|
However, you can conditionally pass logic to omit printing an error, provide colors, or to provide a custom print function:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
var pretty = prettyLog(
|
||||||
|
logColorChooser: (_) => red,
|
||||||
|
printFunction: stderr.writeln,
|
||||||
|
omitError: (r) {
|
||||||
|
var err = r.error;
|
||||||
|
return err is AngelHttpException && err.statusCode != 500;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
myLogger.onRecord.listen(pretty);
|
||||||
|
```
|
1
packages/pretty_logging/analysis_options.yaml
Normal file
1
packages/pretty_logging/analysis_options.yaml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
include: package:lints/recommended.yaml
|
11
packages/pretty_logging/example/main.dart
Normal file
11
packages/pretty_logging/example/main.dart
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:belatuk_pretty_logging/belatuk_pretty_logging.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
Logger.root
|
||||||
|
..level = Level.ALL
|
||||||
|
..onRecord.listen(prettyLog)
|
||||||
|
..info('Hey!')
|
||||||
|
..finest('Bye!')
|
||||||
|
..severe('Oops!', StateError('Wrong!'), StackTrace.current);
|
||||||
|
}
|
50
packages/pretty_logging/lib/belatuk_pretty_logging.dart
Normal file
50
packages/pretty_logging/lib/belatuk_pretty_logging.dart
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:io/ansi.dart';
|
||||||
|
|
||||||
|
/// Prints the contents of a [LogRecord] with pretty colors.
|
||||||
|
///
|
||||||
|
/// By passing [omitError], you can omit printing the error of a given
|
||||||
|
/// [LogRecord].
|
||||||
|
///
|
||||||
|
/// You can also pass a custom [printFunction] or [logColorChooser].
|
||||||
|
void prettyLog(LogRecord record,
|
||||||
|
{bool Function(LogRecord)? omitError,
|
||||||
|
void Function(String)? printFunction,
|
||||||
|
AnsiCode Function(Level)? logColorChooser}) {
|
||||||
|
logColorChooser ??= chooseLogColor;
|
||||||
|
omitError ??= (_) => false;
|
||||||
|
printFunction ??= print;
|
||||||
|
|
||||||
|
var code = logColorChooser(record.level);
|
||||||
|
if (record.error == null) printFunction(code.wrap(record.toString())!);
|
||||||
|
|
||||||
|
if (record.error != null) {
|
||||||
|
var err = record.error;
|
||||||
|
if (omitError(record)) return;
|
||||||
|
printFunction(code.wrap(record.toString() + '\n')!);
|
||||||
|
printFunction(code.wrap(err.toString())!);
|
||||||
|
|
||||||
|
if (record.stackTrace != null) {
|
||||||
|
printFunction(code.wrap(record.stackTrace.toString())!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Chooses a color based on the logger [level].
|
||||||
|
AnsiCode chooseLogColor(Level level) {
|
||||||
|
if (level == Level.SHOUT) {
|
||||||
|
return backgroundRed;
|
||||||
|
} else if (level == Level.SEVERE) {
|
||||||
|
return red;
|
||||||
|
} else if (level == Level.WARNING) {
|
||||||
|
return yellow;
|
||||||
|
} else if (level == Level.INFO) {
|
||||||
|
return cyan;
|
||||||
|
} else if (level == Level.CONFIG ||
|
||||||
|
level == Level.FINE ||
|
||||||
|
level == Level.FINER ||
|
||||||
|
level == Level.FINEST) {
|
||||||
|
return lightGray;
|
||||||
|
}
|
||||||
|
return resetAll;
|
||||||
|
}
|
11
packages/pretty_logging/pubspec.yaml
Normal file
11
packages/pretty_logging/pubspec.yaml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
name: belatuk_pretty_logging
|
||||||
|
version: 4.0.0
|
||||||
|
description: Standalone helper for colorful logging output, using pkg:io AnsiCode.
|
||||||
|
homepage: https://github.com/dart-backend/belatuk-common-utilities/tree/main/packages/pretty_logging
|
||||||
|
environment:
|
||||||
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
|
dependencies:
|
||||||
|
io: ^1.0.0
|
||||||
|
logging: ^1.0.1
|
||||||
|
dev_dependencies:
|
||||||
|
lints: ^1.0.0
|
|
@ -1,6 +1,6 @@
|
||||||
# Belatuk Pub Sub
|
# Belatuk Pub Sub
|
||||||
|
|
||||||
[![version](https://img.shields.io/badge/pub-v4.0.3-brightgreen)](https://pub.dev/packages/belatuk_pub_sub)
|
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/belatuk_pub_sub?include_prereleases)
|
||||||
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
||||||
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/pub_sub/LICENSE)
|
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/pub_sub/LICENSE)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Belatuk Range Header
|
# Belatuk Range Header
|
||||||
|
|
||||||
[![version](https://img.shields.io/badge/pub-v4.0.1-brightgreen)](https://pub.dev/packages/belatuk_range_header)
|
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/belatuk_range_header?include_prereleases)
|
||||||
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
||||||
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/range_header/LICENSE)
|
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/range_header/LICENSE)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Belatuk Symbol Table
|
# Belatuk Symbol Table
|
||||||
|
|
||||||
[![version](https://img.shields.io/badge/pub-v3.0.1-brightgreen)](https://pub.dev/packages/belatuk_symbol_table)
|
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/belatuk_symbol_table?include_prereleases)
|
||||||
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
||||||
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/symbol_table/LICENSE)
|
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/symbol_table/LICENSE)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# User Agent Analyzer
|
# User Agent Analyzer
|
||||||
|
|
||||||
[![version](https://img.shields.io/badge/pub-v3.1.0-brightgreen)](https://pub.dev/packages/user_agent_analyzer)
|
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/user_agent_analyzer?include_prereleases)
|
||||||
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
||||||
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/user_agent/LICENSE)
|
[![License](https://img.shields.io/github/license/dart-backend/belatuk-common-utilities)](https://github.com/dart-backend/belatuk-common-utilities/blob/main/packages/user_agent/LICENSE)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue