257257//// ```
258258
259259import gleam/dict . { type Dict }
260- import gleam/dynamic . { type DecodeError , DecodeError }
260+ import gleam/dynamic
261261import gleam/int
262262import gleam/list
263263import gleam/option . { type Option , None , Some }
@@ -271,14 +271,20 @@ import gleam/result
271271pub type Dynamic =
272272 dynamic . Dynamic
273273
274+ /// Error returned when unexpected data is encountered
275+ ///
276+ pub type DecodeError {
277+ DecodeError ( expected : String , found : String , path : List ( String ) )
278+ }
279+
274280/// A decoder is a value that can be used to turn dynamically typed `Dynamic`
275281/// data into typed data using the `run` function.
276282///
277283/// Several smaller decoders can be combined to make larger decoders using
278284/// functions such as `list` and `field`.
279285///
280286pub opaque type Decoder ( t) {
281- Decoder ( function : fn ( Dynamic ) -> # ( t, List ( dynamic . DecodeError ) ) )
287+ Decoder ( function : fn ( Dynamic ) -> # ( t, List ( DecodeError ) ) )
282288}
283289
284290/// The same as [`field`](#field), except taking a path to the value rather
@@ -339,10 +345,7 @@ pub fn subfield(
339345/// decode.run(data, decoder)
340346/// ```
341347///
342- pub fn run (
343- data : Dynamic ,
344- decoder : Decoder ( t) ,
345- ) -> Result ( t, List ( dynamic . DecodeError ) ) {
348+ pub fn run ( data : Dynamic , decoder : Decoder ( t) ) -> Result ( t, List ( DecodeError ) ) {
346349 let # ( maybe_invalid_data , errors ) = decoder . function ( data )
347350 case errors {
348351 [ ] -> Ok ( maybe_invalid_data )
@@ -392,10 +395,10 @@ pub fn at(path: List(segment), inner: Decoder(a)) -> Decoder(a) {
392395fn index (
393396 path : List ( a) ,
394397 position : List ( a) ,
395- inner : fn ( Dynamic ) -> # ( b, List ( dynamic . DecodeError ) ) ,
398+ inner : fn ( Dynamic ) -> # ( b, List ( DecodeError ) ) ,
396399 data : Dynamic ,
397- handle_miss : fn ( Dynamic , List ( a) ) -> # ( b, List ( dynamic . DecodeError ) ) ,
398- ) -> # ( b, List ( dynamic . DecodeError ) ) {
400+ handle_miss : fn ( Dynamic , List ( a) ) -> # ( b, List ( DecodeError ) ) ,
401+ ) -> # ( b, List ( DecodeError ) ) {
399402 case path {
400403 [ ] -> {
401404 inner ( data )
@@ -477,7 +480,7 @@ pub fn success(data: t) -> Decoder(t) {
477480pub fn decode_error (
478481 expected expected : String ,
479482 found found : Dynamic ,
480- ) -> List ( dynamic . DecodeError ) {
483+ ) -> List ( DecodeError ) {
481484 [ DecodeError ( expected : expected , found : dynamic . classify ( found ) , path : [ ] ) ]
482485}
483486
@@ -601,10 +604,14 @@ fn run_dynamic_function(
601604 data : Dynamic ,
602605 zero : t,
603606 f : dynamic . Decoder ( t) ,
604- ) -> # ( t, List ( dynamic . DecodeError ) ) {
607+ ) -> # ( t, List ( DecodeError ) ) {
605608 case f ( data ) {
606609 Ok ( data ) -> # ( data , [ ] )
607- Error ( errors ) -> # ( zero , errors )
610+ Error ( errors ) -> {
611+ let errors =
612+ list . map ( errors , fn ( e ) { DecodeError ( e . expected , e . found , e . path ) } )
613+ # ( zero , errors )
614+ }
608615 }
609616}
610617
@@ -619,7 +626,7 @@ fn run_dynamic_function(
619626///
620627pub const string : Decoder ( String ) = Decoder ( decode_string )
621628
622- fn decode_string ( data : Dynamic ) -> # ( String , List ( dynamic . DecodeError ) ) {
629+ fn decode_string ( data : Dynamic ) -> # ( String , List ( DecodeError ) ) {
623630 run_dynamic_function ( data , "" , dynamic . string )
624631}
625632
@@ -634,7 +641,7 @@ fn decode_string(data: Dynamic) -> #(String, List(dynamic.DecodeError)) {
634641///
635642pub const bool : Decoder ( Bool ) = Decoder ( decode_bool )
636643
637- fn decode_bool ( data : Dynamic ) -> # ( Bool , List ( dynamic . DecodeError ) ) {
644+ fn decode_bool ( data : Dynamic ) -> # ( Bool , List ( DecodeError ) ) {
638645 run_dynamic_function ( data , False , dynamic . bool )
639646}
640647
@@ -649,7 +656,7 @@ fn decode_bool(data: Dynamic) -> #(Bool, List(dynamic.DecodeError)) {
649656///
650657pub const int : Decoder ( Int ) = Decoder ( decode_int )
651658
652- fn decode_int ( data : Dynamic ) -> # ( Int , List ( dynamic . DecodeError ) ) {
659+ fn decode_int ( data : Dynamic ) -> # ( Int , List ( DecodeError ) ) {
653660 run_dynamic_function ( data , 0 , dynamic . int )
654661}
655662
@@ -664,7 +671,7 @@ fn decode_int(data: Dynamic) -> #(Int, List(dynamic.DecodeError)) {
664671///
665672pub const float : Decoder ( Float ) = Decoder ( decode_float )
666673
667- fn decode_float ( data : Dynamic ) -> # ( Float , List ( dynamic . DecodeError ) ) {
674+ fn decode_float ( data : Dynamic ) -> # ( Float , List ( DecodeError ) ) {
668675 run_dynamic_function ( data , 0.0 , dynamic . float )
669676}
670677
@@ -679,7 +686,7 @@ fn decode_float(data: Dynamic) -> #(Float, List(dynamic.DecodeError)) {
679686///
680687pub const dynamic : Decoder ( Dynamic ) = Decoder ( decode_dynamic )
681688
682- fn decode_dynamic ( data : Dynamic ) -> # ( Dynamic , List ( dynamic . DecodeError ) ) {
689+ fn decode_dynamic ( data : Dynamic ) -> # ( Dynamic , List ( DecodeError ) ) {
683690 # ( data , [ ] )
684691}
685692
@@ -694,7 +701,7 @@ fn decode_dynamic(data: Dynamic) -> #(Dynamic, List(dynamic.DecodeError)) {
694701///
695702pub const bit_array : Decoder ( BitArray ) = Decoder ( decode_bit_array )
696703
697- fn decode_bit_array ( data : Dynamic ) -> # ( BitArray , List ( dynamic . DecodeError ) ) {
704+ fn decode_bit_array ( data : Dynamic ) -> # ( BitArray , List ( DecodeError ) ) {
698705 run_dynamic_function ( data , << >> , dynamic . bit_array )
699706}
700707
@@ -719,11 +726,11 @@ pub fn list(of inner: Decoder(a)) -> Decoder(List(a)) {
719726@ external ( javascript , "../../gleam_stdlib_decode_ffi.mjs" , "list" )
720727fn decode_list (
721728 data : Dynamic ,
722- item : fn ( Dynamic ) -> # ( t, List ( dynamic . DecodeError ) ) ,
729+ item : fn ( Dynamic ) -> # ( t, List ( DecodeError ) ) ,
723730 push_path : fn ( # ( t, List ( DecodeError ) ) , key) -> # ( t, List ( DecodeError ) ) ,
724731 index : Int ,
725732 acc : List ( t) ,
726- ) -> # ( List ( t) , List ( dynamic . DecodeError ) )
733+ ) -> # ( List ( t) , List ( DecodeError ) )
727734
728735/// A decoder that decodes dicts where all keys and vales are decoded with
729736/// given decoders.
@@ -762,12 +769,12 @@ pub fn dict(
762769}
763770
764771fn fold_dict (
765- acc : # ( Dict ( k, v) , List ( dynamic . DecodeError ) ) ,
772+ acc : # ( Dict ( k, v) , List ( DecodeError ) ) ,
766773 key : Dynamic ,
767774 value : Dynamic ,
768- key_decoder : fn ( Dynamic ) -> # ( k, List ( dynamic . DecodeError ) ) ,
769- value_decoder : fn ( Dynamic ) -> # ( v, List ( dynamic . DecodeError ) ) ,
770- ) -> # ( Dict ( k, v) , List ( dynamic . DecodeError ) ) {
775+ key_decoder : fn ( Dynamic ) -> # ( k, List ( DecodeError ) ) ,
776+ value_decoder : fn ( Dynamic ) -> # ( v, List ( DecodeError ) ) ,
777+ ) -> # ( Dict ( k, v) , List ( DecodeError ) ) {
771778 // First we decode the key.
772779 case key_decoder ( key ) {
773780 # ( key , [ ] ) ->
@@ -966,18 +973,24 @@ pub fn failure(zero: a, expected: String) -> Decoder(a) {
966973/// import decode/decode
967974///
968975/// pub fn string_decoder() -> decode.Decoder(String) {
969- /// decode.new_primitive_decoder(dynamic.string, "")
976+ /// let default = ""
977+ /// decode.new_primitive_decoder("String", fn(data) {
978+ /// case dynamic.string {
979+ /// Ok(x) -> Ok(x)
980+ /// Error(x) -> Error(default)
981+ /// }
982+ /// })
970983/// }
971984/// ```
972985///
973986pub fn new_primitive_decoder (
974- decoding_function : fn ( Dynamic ) -> Result ( t , List ( DecodeError ) ) ,
975- zero : t ,
987+ name : String ,
988+ decoding_function : fn ( Dynamic ) -> Result ( t , t ) ,
976989) -> Decoder ( t) {
977990 Decoder ( function : fn ( d ) {
978991 case decoding_function ( d ) {
979992 Ok ( t ) -> # ( t , [ ] )
980- Error ( errors ) -> # ( zero , errors )
993+ Error ( zero ) -> # ( zero , [ DecodeError ( name , dynamic . classify ( d ) , [ ] ) ] )
981994 }
982995 } )
983996}
0 commit comments