diff --git a/.travis.yml b/.travis.yml index 1517deb..36a3453 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: dart dart: - - stable + - beta jobs: include: diff --git a/lib/cast.dart b/lib/cast.dart index f47c028..204f21b 100644 --- a/lib/cast.dart +++ b/lib/cast.dart @@ -58,41 +58,41 @@ class AnyCast extends Cast { class IntCast extends Cast { const IntCast(); core.int _cast(dynamic from, core.String context, dynamic key) => - from is core.int - ? from - : throw new FailedCast(context, key, "$from is not an int"); + from is core.int + ? from + : throw FailedCast(context, key, "$from is not an int"); } class DoubleCast extends Cast { const DoubleCast(); core.double _cast(dynamic from, core.String context, dynamic key) => - from is core.double - ? from - : throw new FailedCast(context, key, "$from is not an double"); + from is core.double + ? from + : throw FailedCast(context, key, "$from is not an double"); } class StringCast extends Cast { const StringCast(); core.String _cast(dynamic from, core.String context, dynamic key) => - from is core.String - ? from - : throw new FailedCast(context, key, "$from is not a String"); + from is core.String + ? from + : throw FailedCast(context, key, "$from is not a String"); } class BoolCast extends Cast { const BoolCast(); core.bool _cast(dynamic from, core.String context, dynamic key) => - from is core.bool - ? from - : throw new FailedCast(context, key, "$from is not a bool"); + from is core.bool + ? from + : throw FailedCast(context, key, "$from is not a bool"); } class Map extends Cast> { final Cast _key; final Cast _value; const Map(Cast key, Cast value) - : _key = key, - _value = value; + : _key = key, + _value = value; core.Map _cast(dynamic from, core.String context, dynamic key) { if (from is core.Map) { var result = {}; @@ -102,7 +102,7 @@ class Map extends Cast> { } return result; } - return throw new FailedCast(context, key, "not a map"); + return throw FailedCast(context, key, "not a map"); } } @@ -110,25 +110,25 @@ class StringMap extends Cast> { final Cast _value; const StringMap(Cast value) : _value = value; core.Map _cast( - dynamic from, core.String context, dynamic key) { + dynamic from, core.String context, dynamic key) { if (from is core.Map) { var result = {}; - for (core.String key in from.keys) { + for (core.String key in from.keys as core.Iterable) { result[key] = _value._cast(from[key], "map entry", key); } return result; } - return throw new FailedCast(context, key, "not a map"); + return throw FailedCast(context, key, "not a map"); } } -class List extends Cast> { +class List extends Cast> { final Cast _entry; const List(Cast entry) : _entry = entry; - core.List _cast(dynamic from, core.String context, dynamic key) { + core.List _cast(dynamic from, core.String context, dynamic key) { if (from is core.List) { var length = from.length; - var result = core.List(length); + var result = core.List.filled(length, null); for (core.int i = 0; i < length; ++i) { if (from[i] != null) { result[i] = _entry._cast(from[i], "list entry", i); @@ -138,28 +138,27 @@ class List extends Cast> { } return result; } - return throw new FailedCast(context, key, "not a list"); + return throw FailedCast(context, key, "not a list"); } } -class Keyed extends Cast> { +class Keyed extends Cast> { Iterable get keys => _map.keys; final core.Map> _map; - const Keyed(core.Map> map) - : _map = map; - core.Map _cast(dynamic from, core.String context, dynamic key) { - core.Map result = {}; + const Keyed(core.Map> map) : _map = map; + core.Map _cast(dynamic from, core.String context, dynamic key) { + core.Map result = {}; if (from is core.Map) { - for (K key in from.keys) { + for (K key in from.keys as core.Iterable) { if (_map.containsKey(key)) { - result[key] = _map[key]._cast(from[key], "map entry", key); + result[key] = _map[key]!._cast(from[key], "map entry", key); } else { result[key] = from[key]; } } return result; } - return throw new FailedCast(context, key, "not a map"); + return throw FailedCast(context, key, "not a map"); } } @@ -167,8 +166,8 @@ class OneOf extends Cast { final Cast _left; final Cast _right; const OneOf(Cast left, Cast right) - : _left = left, - _right = right; + : _left = left, + _right = right; dynamic _cast(dynamic from, core.String context, dynamic key) { try { return _left._cast(from, context, key); @@ -182,10 +181,10 @@ class Apply extends Cast { final Cast _first; final T Function(S) _transform; const Apply(T Function(S) transform, Cast first) - : _transform = transform, - _first = first; + : _transform = transform, + _first = first; T _cast(dynamic from, core.String context, dynamic key) => - _transform(_first._cast(from, context, key)); + _transform(_first._cast(from, context, key)); } class Future extends Cast> { @@ -195,7 +194,7 @@ class Future extends Cast> { if (from is async.Future) { return from.then(_value.cast); } - return throw new FailedCast(context, key, "not a Future"); + return throw FailedCast(context, key, "not a Future"); } } diff --git a/lib/codable.dart b/lib/codable.dart index 6865e7e..aa086d9 100644 --- a/lib/codable.dart +++ b/lib/codable.dart @@ -5,4 +5,4 @@ library codable; export 'src/coding.dart'; export 'src/list.dart'; -export 'src/keyed_archive.dart'; \ No newline at end of file +export 'src/keyed_archive.dart'; diff --git a/lib/src/codable.dart b/lib/src/codable.dart index f341daa..34a1f1a 100644 --- a/lib/src/codable.dart +++ b/lib/src/codable.dart @@ -1,5 +1,5 @@ -import 'package:codable/src/resolver.dart'; +import 'package:conduit_codable/src/resolver.dart'; abstract class Referencable { void resolveOrThrow(ReferenceResolver resolver); -} \ No newline at end of file +} diff --git a/lib/src/coding.dart b/lib/src/coding.dart index 98c5bde..f781027 100644 --- a/lib/src/coding.dart +++ b/lib/src/coding.dart @@ -1,6 +1,6 @@ -import 'package:codable/src/keyed_archive.dart'; +import 'package:conduit_codable/src/keyed_archive.dart'; import 'package:meta/meta.dart'; -import 'package:codable/cast.dart' as cast; +import 'package:conduit_codable/cast.dart' as cast; /// A base class for encodable and decodable objects. /// @@ -8,8 +8,8 @@ import 'package:codable/cast.dart' as cast; /// By overriding [decode] and [encode], an instance of this type will read or write its values /// into a data container that can be transferred into formats like JSON or YAML. abstract class Coding { - Uri referenceURI; - Map> get castMap => null; + Uri? referenceURI; + Map>? get castMap => null; @mustCallSuper void decode(KeyedArchive object) { @@ -19,5 +19,4 @@ abstract class Coding { // would prefer to write referenceURI to object here, but see note in KeyedArchive._encodedObject void encode(KeyedArchive object); - -} \ No newline at end of file +} diff --git a/lib/src/keyed_archive.dart b/lib/src/keyed_archive.dart index 71d07d7..258a74f 100644 --- a/lib/src/keyed_archive.dart +++ b/lib/src/keyed_archive.dart @@ -1,9 +1,9 @@ import 'dart:collection'; -import 'package:codable/src/codable.dart'; -import 'package:codable/src/coding.dart'; -import 'package:codable/cast.dart' as cast; -import 'package:codable/src/list.dart'; -import 'package:codable/src/resolver.dart'; +import 'package:conduit_codable/src/codable.dart'; +import 'package:conduit_codable/src/coding.dart'; +import 'package:conduit_codable/cast.dart' as cast; +import 'package:conduit_codable/src/list.dart'; +import 'package:conduit_codable/src/resolver.dart'; /// A container for a dynamic data object that can be decoded into [Coding] objects. /// @@ -24,7 +24,9 @@ import 'package:codable/src/resolver.dart'; /// final archive = KeyedArchive.archive(person); /// final json = json.encode(archive); /// -class KeyedArchive extends Object with MapMixin implements Referencable { +class KeyedArchive extends Object + with MapMixin + implements Referencable { /// Unarchives [data] into a [KeyedArchive] that can be used by [Coding.decode] to deserialize objects. /// /// Each [Map] in [data] (including [data] itself) is converted to a [KeyedArchive]. @@ -33,10 +35,11 @@ class KeyedArchive extends Object with MapMixin implements Refe /// /// If [allowReferences] is true, JSON Schema references will be traversed and decoded objects /// will contain values from the referenced object. This flag defaults to false. - static KeyedArchive unarchive(Map data, {bool allowReferences: false}) { - final archive = new KeyedArchive(data); + static KeyedArchive unarchive(Map data, + {bool allowReferences = false}) { + final archive = KeyedArchive(data); if (allowReferences) { - archive.resolveOrThrow(new ReferenceResolver(archive)); + archive.resolveOrThrow(ReferenceResolver(archive)); } return archive; } @@ -49,16 +52,17 @@ class KeyedArchive extends Object with MapMixin implements Refe /// /// If [allowReferences] is true, JSON Schema references in the emitted document will be validated. /// Defaults to false. - static Map archive(Coding root, {bool allowReferences: false}) { - final archive = new KeyedArchive({}); + static Map archive(Coding root, + {bool allowReferences = false}) { + final archive = KeyedArchive({}); root.encode(archive); if (allowReferences) { - archive.resolveOrThrow(new ReferenceResolver(archive)); + archive.resolveOrThrow(ReferenceResolver(archive)); } return archive.toPrimitive(); } - KeyedArchive._empty(); + KeyedArchive._empty() : _map = Map(); /// Use [unarchive] instead. KeyedArchive(this._map) { @@ -80,11 +84,11 @@ class KeyedArchive extends Object with MapMixin implements Refe /// ..referenceURI = Uri(path: "/other/object"); /// archive.encodeObject("object", object); /// - Uri referenceURI; + Uri? referenceURI; Map _map; - Coding _inflated; - KeyedArchive _objectReference; + Coding? _inflated; + KeyedArchive? _objectReference; /// Typecast the values in this archive. /// @@ -109,34 +113,34 @@ class KeyedArchive extends Object with MapMixin implements Refe /// // This now becomes a valid assignment /// List key = archive.decode("key"); /// - void castValues(Map schema) { + void castValues(Map? schema) { if (schema == null) { return; } - final caster = new cast.Keyed(schema); + final caster = cast.Keyed(schema); _map = caster.cast(_map); if (_objectReference != null) { // todo: can optimize this by only running it once - _objectReference._map = caster.cast(_objectReference._map); + _objectReference!._map = caster.cast(_objectReference!._map); } } - operator []=(String key, dynamic value) { + operator []=(String key, dynamic? value) { _map[key] = value; } - dynamic operator [](Object key) => _getValue(key); + dynamic? operator [](Object? key) => _getValue(key as String); Iterable get keys => _map.keys; void clear() => _map.clear(); - dynamic remove(Object key) => _map.remove(key); + dynamic remove(Object? key) => _map.remove(key); - Map toPrimitive() { - final out = {}; + Map toPrimitive() { + final out = {}; _map.forEach((key, val) { if (val is KeyedArchive) { out[key] = val.toPrimitive(); @@ -149,7 +153,7 @@ class KeyedArchive extends Object with MapMixin implements Refe return out; } - dynamic _getValue(String key) { + dynamic _getValue(String? key) { if (_map.containsKey(key)) { return _map[key]; } @@ -163,12 +167,12 @@ class KeyedArchive extends Object with MapMixin implements Refe keys.forEach((key) { final val = _map[key]; if (val is Map) { - _map[key] = new KeyedArchive(caster.cast(val)); + _map[key] = KeyedArchive(caster.cast(val)); } else if (val is List) { - _map[key] = new ListArchive.from(val); + _map[key] = ListArchive.from(val); } else if (key == r"$ref") { if (val is Map) { - _objectReference = val; + _objectReference = val as KeyedArchive?; } else { referenceURI = Uri.parse(Uri.parse(val).fragment); } @@ -182,9 +186,10 @@ class KeyedArchive extends Object with MapMixin implements Refe @override void resolveOrThrow(ReferenceResolver coder) { if (referenceURI != null) { - _objectReference = coder.resolve(referenceURI); + _objectReference = coder.resolve(referenceURI!); if (_objectReference == null) { - throw new ArgumentError("Invalid document. Reference '#${referenceURI.path}' does not exist in document."); + throw ArgumentError( + "Invalid document. Reference '#${referenceURI!.path}' does not exist in document."); } } @@ -199,17 +204,17 @@ class KeyedArchive extends Object with MapMixin implements Refe /* decode */ - T _decodedObject(KeyedArchive raw, T inflate()) { + T? _decodedObject(KeyedArchive? raw, T inflate()) { if (raw == null) { return null; } if (raw._inflated == null) { raw._inflated = inflate(); - raw._inflated.decode(raw); + raw._inflated!.decode(raw); } - return raw._inflated; + return raw._inflated as T?; } /// Returns the object associated by [key]. @@ -221,15 +226,15 @@ class KeyedArchive extends Object with MapMixin implements Refe /// If this object is a reference to another object (via [referenceURI]), this object's key-value /// pairs will be searched first. If [key] is not found, the referenced object's key-values pairs are searched. /// If no match is found, null is returned. - T decode(String key) { + T? decode(String key) { var v = _getValue(key); if (v == null) { return null; } - if (T == Uri) { + if (T is Uri) { return Uri.parse(v) as T; - } else if (T == DateTime) { + } else if (T is DateTime) { return DateTime.parse(v) as T; } @@ -241,15 +246,15 @@ class KeyedArchive extends Object with MapMixin implements Refe /// [inflate] must create an empty instance of [T]. The value associated with [key] /// must be a [KeyedArchive] (a [Map]). The values of the associated object are read into /// the empty instance of [T]. - T decodeObject(String key, T inflate()) { + T? decodeObject(String key, T inflate()) { final val = _getValue(key); if (val == null) { return null; } if (val is! KeyedArchive) { - throw new ArgumentError( - "Cannot decode key '$key' into '$T', because the value is not a Map. Actual value: '$val'."); + throw ArgumentError( + "Cannot decode key '$key' into '$T', because the value is not a Map. Actual value: '$val'."); } return _decodedObject(val, inflate); @@ -261,17 +266,17 @@ class KeyedArchive extends Object with MapMixin implements Refe /// must be a [ListArchive] (a [List] of [Map]). For each element of the archived list, /// [inflate] is invoked and each object in the archived list is decoded into /// the instance of [T]. - List decodeObjects(String key, T inflate()) { + List? decodeObjects(String key, T? inflate()) { var val = _getValue(key); if (val == null) { return null; } if (val is! List) { - throw new ArgumentError( - "Cannot decode key '$key' as 'List<$T>', because value is not a List. Actual value: '$val'."); + throw ArgumentError( + "Cannot decode key '$key' as 'List<$T>', because value is not a List. Actual value: '$val'."); } - return (val as List).map((v) => _decodedObject(v, inflate)).toList().cast(); + return val.map((v) => _decodedObject(v, inflate)).toList().cast(); } /// Returns a map of [T]s associated with [key]. @@ -280,22 +285,24 @@ class KeyedArchive extends Object with MapMixin implements Refe /// must be a [KeyedArchive] (a [Map]), where each value is a [T]. /// For each key-value pair of the archived map, [inflate] is invoked and /// each value is decoded into the instance of [T]. - Map decodeObjectMap(String key, T inflate()) { + Map? decodeObjectMap(String key, T inflate()) { var v = _getValue(key); if (v == null) { return null; } if (v is! Map) { - throw new ArgumentError("Cannot decode key '$key' as 'Map', because value is not a Map. Actual value: '$v'."); + throw ArgumentError( + "Cannot decode key '$key' as 'Map', because value is not a Map. Actual value: '$v'."); } - return new Map.fromIterable(v.keys, key: (k) => k, value: (k) => _decodedObject(v[k], inflate)); + return Map.fromIterable(v.keys, + key: (k) => k, value: (k) => _decodedObject(v[k], inflate)); } /* encode */ - Map _encodedObject(Coding object) { + Map? _encodedObject(Coding? object) { if (object == null) { return null; } @@ -305,9 +312,11 @@ class KeyedArchive extends Object with MapMixin implements Refe // they are currently not being emitted. the solution is probably tricky. // letting encode run as normal would stack overflow when there is a cyclic // reference between this object and another. - var json = new KeyedArchive._empty().._map = {}..referenceURI = object.referenceURI; + var json = KeyedArchive._empty() + .._map = {} + ..referenceURI = object.referenceURI; if (json.referenceURI != null) { - json._map[r"$ref"] = Uri(fragment: json.referenceURI.path).toString(); + json._map[r"$ref"] = Uri(fragment: json.referenceURI!.path).toString(); } else { object.encode(json); } @@ -339,7 +348,7 @@ class KeyedArchive extends Object with MapMixin implements Refe /// /// This invokes [Coding.encode] on [value] and adds the object /// to this archive for the key [key]. - void encodeObject(String key, Coding value) { + void encodeObject(String key, Coding? value) { if (value == null) { return; } @@ -351,19 +360,19 @@ class KeyedArchive extends Object with MapMixin implements Refe /// /// This invokes [Coding.encode] on each object in [value] and adds the list of objects /// to this archive for the key [key]. - void encodeObjects(String key, List value) { + void encodeObjects(String key, List? value) { if (value == null) { return; } - _map[key] = new ListArchive.from(value.map((v) => _encodedObject(v)).toList()); + _map[key] = ListArchive.from(value.map((v) => _encodedObject(v)).toList()); } /// Encodes map of [Coding] objects into this object for [key]. /// /// This invokes [Coding.encode] on each value in [value] and adds the map of objects /// to this archive for the key [key]. - void encodeObjectMap(String key, Map value) { + void encodeObjectMap(String key, Map? value) { if (value == null) { return; } @@ -376,4 +385,3 @@ class KeyedArchive extends Object with MapMixin implements Refe _map[key] = object; } } - diff --git a/lib/src/list.dart b/lib/src/list.dart index 2726ae8..21b5f92 100644 --- a/lib/src/list.dart +++ b/lib/src/list.dart @@ -1,28 +1,30 @@ import 'dart:collection'; -import 'package:codable/src/codable.dart'; -import 'package:codable/src/coding.dart'; -import 'package:codable/src/keyed_archive.dart'; -import 'package:codable/src/resolver.dart'; +import 'package:conduit_codable/src/codable.dart'; +import 'package:conduit_codable/src/coding.dart'; +import 'package:conduit_codable/src/keyed_archive.dart'; +import 'package:conduit_codable/src/resolver.dart'; /// A list of values in a [KeyedArchive]. /// /// This object is a [List] that has additional behavior for encoding and decoding [Coding] objects. -class ListArchive extends Object with ListMixin implements Referencable { +class ListArchive extends Object + with ListMixin + implements Referencable { final List _inner; ListArchive() : _inner = []; /// Replaces all instances of [Map] and [List] in this object with [KeyedArchive] and [ListArchive]s. ListArchive.from(List raw) - : _inner = raw.map((e) { - if (e is Map) { - return KeyedArchive(e); - } else if (e is List) { - return ListArchive.from(e); - } - return e; - }).toList(); + : _inner = raw.map((e) { + if (e is Map) { + return KeyedArchive(e); + } else if (e is List) { + return ListArchive.from(e); + } + return e; + }).toList(); @override operator [](int index) => _inner[index]; diff --git a/lib/src/resolver.dart b/lib/src/resolver.dart index 79d8a50..4ab2194 100644 --- a/lib/src/resolver.dart +++ b/lib/src/resolver.dart @@ -1,13 +1,19 @@ -import 'package:codable/src/keyed_archive.dart'; +import 'package:conduit_codable/src/keyed_archive.dart'; class ReferenceResolver { ReferenceResolver(this.document); final KeyedArchive document; - KeyedArchive resolve(Uri ref) { - return ref.pathSegments.fold(document, (objectPtr, pathSegment) { - return objectPtr[pathSegment] as Map; - }) as KeyedArchive; + KeyedArchive? resolve(Uri ref) { + var folded = ref.pathSegments.fold(document, + (KeyedArchive? objectPtr, pathSegment) { + if (objectPtr != null) + return objectPtr[pathSegment]; // as Map; + else + return null; + }); + + return folded; } -} \ No newline at end of file +} diff --git a/pubspec.yaml b/pubspec.yaml index 71d6909..60d755f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,14 +1,12 @@ -name: codable +name: conduit_codable description: A serialization library for converting dynamic, structured data (JSON, YAML) into Dart types. -version: 1.0.0 -homepage: https://github.com/stablekernel/dart-codable -author: stable|kernel +version: 1.0.0-b1 +homepage: https://github.com/conduit-dart/dart-codable environment: - sdk: '>=2.0.0 <3.0.0' + sdk: '>=2.12.0 <3.0.0' dependencies: - meta: ^1.1.5 dev_dependencies: - test: ^1.3.0 + test: ^1.16.4 diff --git a/test/decode_test.dart b/test/decode_test.dart index 5862563..9d012bd 100644 --- a/test/decode_test.dart +++ b/test/decode_test.dart @@ -1,14 +1,14 @@ import 'dart:convert'; -import 'package:codable/codable.dart'; +import 'package:conduit_codable/codable.dart'; import 'package:test/test.dart'; -import 'package:codable/cast.dart' as cast; +import 'package:conduit_codable/cast.dart' as cast; void main() { group("Primitive decode", () { test("Can decode primitive type", () { final archive = getJSONArchive({"key": 2}); - int val = archive.decode("key"); + int? val = archive.decode("key"); expect(val, 2); }); @@ -16,7 +16,7 @@ void main() { final archive = getJSONArchive({ "key": [1, "2"] }); - List l = archive.decode("key"); + List? l = archive.decode("key"); expect(l, [1, "2"]); }); @@ -24,32 +24,32 @@ void main() { final archive = getJSONArchive({ "key": {"key": "val"} }); - Map d = archive.decode("key"); + KeyedArchive? d = archive.decode("key"); expect(d, {"key": "val"}); }); test("Can decode URI", () { final archive = getJSONArchive({"key": "https://host.com"}); - Uri d = archive.decode("key"); - expect(d.host, "host.com"); + Uri? d = archive.decode("key"); + expect(d!.host, "host.com"); }); test("Can decode DateTime", () { - final date = new DateTime.now(); + final date = DateTime.now(); final archive = getJSONArchive({"key": date.toIso8601String()}); - DateTime d = archive.decode("key"); - expect(d.isAtSameMomentAs(date), true); + DateTime? d = archive.decode("key"); + expect(d!.isAtSameMomentAs(date), true); }); test("If value is null, return null from decode", () { final archive = getJSONArchive({"key": null}); - int val = archive.decode("key"); + int? val = archive.decode("key"); expect(val, isNull); }); test("If archive does not contain key, return null from decode", () { final archive = getJSONArchive({}); - int val = archive.decode("key"); + int? val = archive.decode("key"); expect(val, isNull); }); }); @@ -60,7 +60,7 @@ void main() { "key": {"key": "val"} }); archive.castValues({"key": cast.Map(cast.String, cast.String)}); - Map d = archive.decode("key"); + Map? d = archive.decode("key"); expect(d, {"key": "val"}); }); @@ -70,27 +70,29 @@ void main() { "key": ["val"] } }); - archive.castValues({"key": cast.Map(cast.String, cast.List(cast.String))}); - Map> d = archive.decode("key"); + archive + .castValues({"key": cast.Map(cast.String, cast.List(cast.String))}); + Map>? d = archive.decode("key"); expect(d, { "key": ["val"] }); }); - test("Can decode Map> where elements are null", () { + test("Can decode Map> where elements are null", () { final archive = getJSONArchive({ "key": { "key": [null, null] } }); - archive.castValues({"key": cast.Map(cast.String, cast.List(cast.String))}); - Map> d = archive.decode("key"); + archive + .castValues({"key": cast.Map(cast.String, cast.List(cast.String))}); + Map>? d = archive.decode("key"); expect(d, { "key": [null, null] }); }); - test("Can decode Map>>", () { + test("Can decode Map>>", () { final archive = getJSONArchive({ "key": { "key": { @@ -98,8 +100,11 @@ void main() { } } }); - archive.castValues({"key": cast.Map(cast.String, cast.Map(cast.String, cast.List(cast.String)))}); - Map>> d = archive.decode("key"); + archive.castValues({ + "key": + cast.Map(cast.String, cast.Map(cast.String, cast.List(cast.String))) + }); + Map>>? d = archive.decode("key"); expect(d, { "key": { "key": ["val", null] @@ -114,7 +119,7 @@ void main() { "key": ["val", null] }); archive.castValues({"key": cast.List(cast.String)}); - List d = archive.decode("key"); + List? d = archive.decode("key"); expect(d, ["val", null]); }); @@ -127,8 +132,9 @@ void main() { null ] }); - archive.castValues({"key": cast.List(cast.Map(cast.String, cast.List(cast.String)))}); - List>> d = archive.decode("key"); + archive.castValues( + {"key": cast.List(cast.Map(cast.String, cast.List(cast.String)))}); + List>?>? d = archive.decode("key"); expect(d, [ { "key": ["val", null] @@ -143,7 +149,7 @@ void main() { final archive = getJSONArchive({ "key": {"name": "Bob"} }); - Parent p = archive.decodeObject("key", () => Parent()); + Parent p = archive.decodeObject("key", () => Parent())!; expect(p.name, "Bob"); expect(p.child, isNull); expect(p.children, isNull); @@ -170,13 +176,15 @@ void main() { {"name": "Sally"} ] }); - List p = archive.decodeObjects("key", () => Parent()); - expect(p[0].name, "Bob"); + List? p = archive.decodeObjects("key", () => Parent()); + expect(p![0]!.name, "Bob"); expect(p[1], isNull); - expect(p[2].name, "Sally"); + expect(p[2]!.name, "Sally"); }); - test("If coding object list is paired with non-List, an exception is thrown", () { + test( + "If coding object list is paired with non-List, an exception is thrown", + () { final archive = getJSONArchive({ "key": {"name": "Bob"} }); @@ -186,7 +194,9 @@ void main() { } on ArgumentError {} }); - test("If any element of coding list is not a coding object, an exception is thrown", () { + test( + "If any element of coding list is not a coding object, an exception is thrown", + () { final archive = getJSONArchive({ "key": [ {"name": "Bob"}, @@ -207,13 +217,14 @@ void main() { } }); - final map = archive.decodeObjectMap("key", () => Parent()); + final map = archive.decodeObjectMap("key", () => Parent())!; expect(map.length, 2); - expect(map["1"].name, "Bob"); + expect(map["1"]!.name, "Bob"); expect(map["2"], isNull); }); - test("If coding object map is paired with non-Map, an exception is thrown", () { + test("If coding object map is paired with non-Map, an exception is thrown", + () { final archive = getJSONArchive({"key": []}); try { archive.decodeObjectMap("key", () => Parent()); @@ -221,7 +232,9 @@ void main() { } on ArgumentError {} }); - test("If any element of coding map is not a coding object, an exception is thrown", () { + test( + "If any element of coding map is not a coding object, an exception is thrown", + () { final archive = getJSONArchive({ "key": {"1": "2"} }); @@ -241,9 +254,9 @@ void main() { } }); - final o = archive.decodeObject("key", () => Parent()); + final o = archive.decodeObject("key", () => Parent())!; expect(o.name, "Bob"); - expect(o.child.name, "Sally"); + expect(o.child!.name, "Sally"); expect(o.childMap, isNull); expect(o.children, isNull); }); @@ -258,12 +271,12 @@ void main() { } }); - final o = archive.decodeObject("key", () => Parent()); + final o = archive.decodeObject("key", () => Parent())!; expect(o.name, "Bob"); expect(o.child, isNull); expect(o.childMap, isNull); - expect(o.children.length, 1); - expect(o.children.first.name, "Sally"); + expect(o.children!.length, 1); + expect(o.children?.first?.name, "Sally"); }); test("Can decode map of nested objects", () { @@ -276,12 +289,12 @@ void main() { } }); - final o = archive.decodeObject("key", () => Parent()); + final o = archive.decodeObject("key", () => Parent())!; expect(o.name, "Bob"); expect(o.children, isNull); expect(o.child, isNull); - expect(o.childMap.length, 1); - expect(o.childMap["sally"].name, "Sally"); + expect(o.childMap!.length, 1); + expect(o.childMap!["sally"]!.name, "Sally"); }); }); @@ -295,13 +308,15 @@ void main() { } }, allowReferences: true); - final p = archive.decodeObject("parent", () => Parent()); + final p = archive.decodeObject("parent", () => Parent())!; expect(p.name, "Bob"); - expect(p.child.name, "Sally"); - expect(p.child.parent, isNull); + expect(p.child!.name, "Sally"); + expect(p.child!.parent, isNull); }); - test("If reference doesn't exist, an error is thrown when creating document", () { + test( + "If reference doesn't exist, an error is thrown when creating document", + () { try { getJSONArchive({ "parent": { @@ -320,32 +335,41 @@ void main() { "child": {"name": "Sally"}, "parent": { "name": "Bob", - "children": [{"\$ref": "#/child"}, {"name": "fred"}] + "children": [ + {"\$ref": "#/child"}, + {"name": "fred"} + ] } }, allowReferences: true); - final p = archive.decodeObject("parent", () => Parent()); + final p = archive.decodeObject("parent", () => Parent())!; expect(p.name, "Bob"); - expect(p.children.first.name, "Sally"); - expect(p.children.last.name, "fred"); + expect(p.children?.first?.name, "Sally"); + expect(p.children?.last?.name, "fred"); }); test("Cyclical references are resolved", () { final archive = getJSONArchive({ - "child": {"name": "Sally", "parent": {"\$ref": "#/parent"}}, + "child": { + "name": "Sally", + "parent": {"\$ref": "#/parent"} + }, "parent": { "name": "Bob", - "children": [{"\$ref": "#/child"}, {"name": "fred"}] + "children": [ + {"\$ref": "#/child"}, + {"name": "fred"} + ] } }, allowReferences: true); - final p = archive.decodeObject("parent", () => Parent()); + final p = archive.decodeObject("parent", () => Parent())!; expect(p.name, "Bob"); - expect(p.children.first.name, "Sally"); - expect(p.children.first.parent.name, "Bob"); - expect(p.children.last.name, "fred"); + expect(p.children?.first?.name, "Sally"); + expect(p.children?.first?.parent!.name, "Bob"); + expect(p.children?.last?.name, "fred"); - expect(p.hashCode, isNot(p.children.first.parent.hashCode)); + expect(p.hashCode, isNot(p.children?.first?.parent.hashCode)); }); test("Can override castMap to coerce values", () { @@ -355,30 +379,28 @@ void main() { "things": ["value"] } }); - final p = archive.decodeObject("key", () => Parent()); + final p = archive.decodeObject("key", () => Parent())!; expect(p.things, ["value"]); }); }); - } /// Strips type info from data -KeyedArchive getJSONArchive(dynamic data, {bool allowReferences: false}) { - return KeyedArchive.unarchive(json.decode(json.encode(data)), allowReferences: allowReferences); +KeyedArchive getJSONArchive(dynamic data, {bool allowReferences = false}) { + return KeyedArchive.unarchive(json.decode(json.encode(data)), + allowReferences: allowReferences); } class Parent extends Coding { - String name; - Child child; - List children; - Map childMap; - List things; + String? name; + Child? child; + List? children; + Map? childMap; + List? things; @override Map> get castMap { - return { - "things": cast.List(cast.String) - }; + return {"things": cast.List(cast.String)}; } @override @@ -397,9 +419,9 @@ class Parent extends Coding { } class Child extends Coding { - String name; + String? name; - Parent parent; + Parent? parent; @override void decode(KeyedArchive object) { diff --git a/test/encode_test.dart b/test/encode_test.dart index c4f313b..8a07e11 100644 --- a/test/encode_test.dart +++ b/test/encode_test.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:codable/codable.dart'; +import 'package:conduit_codable/codable.dart'; import 'package:test/test.dart'; void main() { @@ -44,10 +44,10 @@ void main() { test("Can encode DateTime", () { final out = encode((obj) { - obj.encode("key", new DateTime(2000)); + obj.encode("key", DateTime(2000)); }); - expect(out, {"key": new DateTime(2000).toIso8601String()}); + expect(out, {"key": DateTime(2000).toIso8601String()}); }); test("If value is null, do not include key", () { @@ -72,7 +72,8 @@ void main() { test("Can encode list of Coding objects", () { final out = encode((object) { - object.encodeObject("key", Parent("Bob", children: [Child("Fred"), null, Child("Sally")])); + object.encodeObject("key", + Parent("Bob", children: [Child("Fred"), null, Child("Sally")])); }); expect(out, { @@ -90,7 +91,12 @@ void main() { test("Can encode map of Coding objects", () { final out = encode((object) { object.encodeObject( - "key", Parent("Bob", childMap: {"fred": Child("Fred"), "null": null, "sally": Child("Sally")})); + "key", + Parent("Bob", childMap: { + "fred": Child("Fred"), + "null": null, + "sally": Child("Sally") + })); }); expect(out, { @@ -109,7 +115,9 @@ void main() { group("Coding object references", () { test("Parent can contain reference to child in single object encode", () { final container = Container( - Parent("Bob", child: Child._()..referenceURI = Uri(path: "/definitions/child")), {"child": Child("Sally")}); + Parent("Bob", + child: Child._()..referenceURI = Uri(path: "/definitions/child")), + {"child": Child("Sally")}); final out = KeyedArchive.archive(container, allowReferences: true); expect(out, { @@ -123,8 +131,13 @@ void main() { }); }); - test("If reference doesn't exist, an error is thrown when creating document", () { - final container = Container(Parent("Bob", child: Child._()..referenceURI = Uri(path: "/definitions/child")), {}); + test( + "If reference doesn't exist, an error is thrown when creating document", + () { + final container = Container( + Parent("Bob", + child: Child._()..referenceURI = Uri(path: "/definitions/child")), + {}); try { KeyedArchive.archive(container, allowReferences: true); @@ -134,9 +147,14 @@ void main() { } }); - test("If reference doesn't exist in objectMap, an error is thrown when creating document", () { - final container = - Container(Parent("Bob", childMap: {"c": Child._()..referenceURI = Uri(path: "/definitions/child")}), {}); + test( + "If reference doesn't exist in objectMap, an error is thrown when creating document", + () { + final container = Container( + Parent("Bob", childMap: { + "c": Child._()..referenceURI = Uri(path: "/definitions/child") + }), + {}); try { KeyedArchive.archive(container, allowReferences: true); @@ -146,9 +164,14 @@ void main() { } }); - test("If reference doesn't exist in objectList, an error is thrown when creating document", () { - final container = - Container(Parent("Bob", children: [Child._()..referenceURI = Uri(path: "/definitions/child")]), {}); + test( + "If reference doesn't exist in objectList, an error is thrown when creating document", + () { + final container = Container( + Parent("Bob", children: [ + Child._()..referenceURI = Uri(path: "/definitions/child") + ]), + {}); try { KeyedArchive.archive(container, allowReferences: true); @@ -160,7 +183,10 @@ void main() { test("Parent can contain reference to child in a list of objects", () { final container = Container( - Parent("Bob", children: [Child("Sally"), Child._()..referenceURI = Uri(path: "/definitions/child")]), + Parent("Bob", children: [ + Child("Sally"), + Child._()..referenceURI = Uri(path: "/definitions/child") + ]), {"child": Child("Fred")}); final out = KeyedArchive.archive(container, allowReferences: true); @@ -180,8 +206,10 @@ void main() { test("Parent can contain reference to child in a map of objects", () { final container = Container( - Parent("Bob", - childMap: {"sally": Child("Sally"), "ref": Child._()..referenceURI = Uri(path: "/definitions/child")}), + Parent("Bob", childMap: { + "sally": Child("Sally"), + "ref": Child._()..referenceURI = Uri(path: "/definitions/child") + }), {"child": Child("Fred")}); final out = KeyedArchive.archive(container, allowReferences: true); @@ -201,8 +229,14 @@ void main() { test("Cyclical references are resolved", () { final container = Container( - Parent("Bob", children: [Child("Sally"), Child._()..referenceURI = Uri(path: "/definitions/child")]), - {"child": Child("Fred", parent: Parent._()..referenceURI = Uri(path: "/root"))}); + Parent("Bob", children: [ + Child("Sally"), + Child._()..referenceURI = Uri(path: "/definitions/child") + ]), + { + "child": Child("Fred", + parent: Parent._()..referenceURI = Uri(path: "/root")) + }); final out = KeyedArchive.archive(container, allowReferences: true); final expected = { @@ -228,7 +262,7 @@ void main() { // and ensure that our data is valid json final washedData = json.decode(json.encode(out)); final doc = KeyedArchive.unarchive(washedData); - final decodedContainer = new Container._()..decode(doc); + final decodedContainer = Container._()..decode(doc); final reencodedArchive = KeyedArchive.archive(decodedContainer); expect(reencodedArchive, expected); }); @@ -259,8 +293,8 @@ void main() { }); } -Map encode(void encoder(KeyedArchive object)) { - final archive = new KeyedArchive({}); +Map? encode(void encoder(KeyedArchive object)) { + final archive = KeyedArchive({}); encoder(archive); return json.decode(json.encode(archive)); } @@ -270,14 +304,14 @@ class Container extends Coding { Container(this.root, this.definitions); - Parent root; - Map definitions; + Parent? root; + Map? definitions; @override void decode(KeyedArchive object) { super.decode(object); - root = object.decodeObject("root", () => Parent._()); + root = object.decodeObject("root", () => Parent._())!; definitions = object.decodeObjectMap("definitions", () => Child._()); } @@ -293,11 +327,11 @@ class Parent extends Coding { Parent(this.name, {this.child, this.children, this.childMap, this.things}); - String name; - Child child; - List children; - Map childMap; - List things; + String? name; + Child? child; + List? children; + Map? childMap; + List? things; @override void decode(KeyedArchive object) { @@ -324,8 +358,8 @@ class Child extends Coding { Child(this.name, {this.parent}); - String name; - Parent parent; + String? name; + Parent? parent; @override void decode(KeyedArchive object) {