@kaiko.io/rescript-deser 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Makefile +4 -1
- package/README.md +79 -2
- package/bsconfig.json +5 -1
- package/package.json +7 -2
- package/src/JSON.res +8 -29
- package/tests/compile.res +22 -0
package/Makefile
CHANGED
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ module MyData = {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
module MyDataDeserializer = JSON.
|
|
28
|
+
module MyDataDeserializer = JSON.MakeDeserializer({
|
|
29
29
|
type t = MyData.t
|
|
30
30
|
open JSON.Field
|
|
31
31
|
|
|
@@ -36,7 +36,84 @@ module MyDataDeserializer = JSON.Deserializer({
|
|
|
36
36
|
})
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
The resultant module has type:
|
|
40
|
+
|
|
41
|
+
```rescript
|
|
42
|
+
module type Deserializer = {
|
|
43
|
+
type t
|
|
44
|
+
let name: string
|
|
45
|
+
let fromJSON: Js.Json.t => result<t, string>
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The input module must have the module type:
|
|
50
|
+
|
|
51
|
+
```rescript
|
|
52
|
+
module type Serializable = {
|
|
53
|
+
type t
|
|
54
|
+
let fields: Field.t
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
### List of variants for `Field.t`.
|
|
60
|
+
|
|
61
|
+
- `String`, parses a JSON string into a ReScript `string`.
|
|
62
|
+
|
|
63
|
+
- `Int`, parses a JSON number into a ReScript `int`
|
|
64
|
+
|
|
65
|
+
- `Float`, parses a JSON number into a ReScript `float`
|
|
66
|
+
|
|
67
|
+
- `Boolean`
|
|
68
|
+
|
|
69
|
+
- `Any`, *unsafe type* to allow anything. The result is the same underlying
|
|
70
|
+
JS representation of the object that comes from the JSON data.
|
|
71
|
+
|
|
72
|
+
- `Date`, parses either a string representation of a date (datetime) or a
|
|
73
|
+
floating point representation of date (datetime) into `Js.Date.t`; we make
|
|
74
|
+
sure the result is valid and won't return NaN afterwards.
|
|
75
|
+
|
|
76
|
+
This basically calls, `Js.Date.fromString` or `Js.Date.fromFloat`; and tests
|
|
77
|
+
the resulting value.
|
|
78
|
+
|
|
79
|
+
`Datetime` is an alias for `Date`.
|
|
80
|
+
|
|
81
|
+
- `Optional(Field.t)`, allow the field to be missing from the JSON data in
|
|
82
|
+
which case, return `None`; if the field is present and valid return
|
|
83
|
+
`Some(value)`.
|
|
84
|
+
|
|
85
|
+
- `OptionalWithDefault(Field.t, FieldValue.t)`; same as optional but return a
|
|
86
|
+
default value instead. Notice, this is unsafe if the actual type of the
|
|
87
|
+
default value does not match the expected type.
|
|
88
|
+
|
|
89
|
+
- `Tuple(array<Field.t>)`, parses a JSON list with an exact number of items of
|
|
90
|
+
varying types.
|
|
91
|
+
|
|
92
|
+
- `Object(array<(string, Field.t)>)`, parses a JSON object that should have
|
|
93
|
+
exactly the fields described; missing items are not allowed unless they are
|
|
94
|
+
`Optional`, `OptionalWithDefault`.
|
|
95
|
+
|
|
96
|
+
- `Mapping(Field.t)`, parses a JSON object with unknown keys (of type string)
|
|
97
|
+
and a given type of value. Valid values have the internal type
|
|
98
|
+
`Prelude.Dict.t`.
|
|
99
|
+
|
|
100
|
+
- `Deserializer(module(Deserializer))`, parses an JSON object with the function
|
|
101
|
+
`fromJSON` of another deserializer. This allows the composition of
|
|
102
|
+
deserializers.
|
|
103
|
+
|
|
104
|
+
- `Collection(module(Deserializer))`, parses a list of items with the function
|
|
105
|
+
`fromJSON` of another deserializer. Invalid items are ignored.
|
|
106
|
+
|
|
107
|
+
This is basically a shortcut to
|
|
108
|
+
`Array(DefaultWhenInvalid(Optional(Deserializer(module(M))),
|
|
109
|
+
FieldValue.null))`, with the additional post-processing to remove `None`
|
|
110
|
+
values.
|
|
111
|
+
|
|
112
|
+
- `DefaultWhenInvalid(Field.t, FieldValue.t)`, if the JSON contains an invalid
|
|
113
|
+
value, use a default instead.
|
|
114
|
+
|
|
115
|
+
- `Array(Field.t)`, parses a JSON list with homogeneous items.
|
|
116
|
+
|
|
40
117
|
|
|
41
118
|
## Current limitations with recursive data
|
|
42
119
|
|
package/bsconfig.json
CHANGED
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaiko.io/rescript-deser",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"json",
|
|
6
|
+
"deserializer",
|
|
7
|
+
"rescript"
|
|
8
|
+
],
|
|
4
9
|
"description": "Simple JSON deserializer for ReScript",
|
|
5
|
-
"repository": "https://gitlab.com/kaiko-systems/
|
|
10
|
+
"repository": "https://gitlab.com/kaiko-systems/rescript-deser",
|
|
6
11
|
"author": "Kaiko Systems <info@kaikosystems.com>",
|
|
7
12
|
"license": "MIT",
|
|
8
13
|
"private": false,
|
package/src/JSON.res
CHANGED
|
@@ -23,7 +23,7 @@ module FieldValue = {
|
|
|
23
23
|
exception TypeError(string)
|
|
24
24
|
|
|
25
25
|
@doc("The module type of a built deserializer which is suitable to add as a subparser.")
|
|
26
|
-
module type
|
|
26
|
+
module type Deserializer = {
|
|
27
27
|
type t
|
|
28
28
|
let name: string
|
|
29
29
|
let fromJSON: Js.Json.t => result<t, string>
|
|
@@ -54,13 +54,13 @@ module Field = {
|
|
|
54
54
|
/// expected entries.
|
|
55
55
|
| Mapping(t)
|
|
56
56
|
|
|
57
|
-
| Deserializer(module(
|
|
57
|
+
| Deserializer(module(Deserializer))
|
|
58
58
|
|
|
59
59
|
/// A specialized Array of deserialized items that ignores unparsable
|
|
60
60
|
/// items and returns the valid collection. This saves the user from
|
|
61
61
|
/// writing 'Array(DefaultWhenInvalid(Optional(Deserializer(module(M)))))'
|
|
62
62
|
/// and then post-process the list of items with 'Array.keepSome'
|
|
63
|
-
| Collection(module(
|
|
63
|
+
| Collection(module(Deserializer))
|
|
64
64
|
| DefaultWhenInvalid(t, FieldValue.t)
|
|
65
65
|
|
|
66
66
|
// FIXME: this is used to add additional restrictions like variadictInt or
|
|
@@ -105,7 +105,7 @@ module Field = {
|
|
|
105
105
|
| Datetime
|
|
106
106
|
| Date => "Date"
|
|
107
107
|
| Collection(m) => {
|
|
108
|
-
module M = unpack(m:
|
|
108
|
+
module M = unpack(m: Deserializer)
|
|
109
109
|
"Collection of " ++ M.name
|
|
110
110
|
}
|
|
111
111
|
|
|
@@ -122,7 +122,7 @@ module Field = {
|
|
|
122
122
|
| Mapping(t) => `Mapping of ${t->toString}`
|
|
123
123
|
| Morphism(t, _) => t->toString ++ " to apply a morphism"
|
|
124
124
|
| Deserializer(m) => {
|
|
125
|
-
module M = unpack(m:
|
|
125
|
+
module M = unpack(m: Deserializer)
|
|
126
126
|
M.name
|
|
127
127
|
}
|
|
128
128
|
|
|
@@ -216,7 +216,7 @@ module Field = {
|
|
|
216
216
|
| (Morphism(shape, f), _) => untagged->fromUntagged(shape)->f->FieldValue.any
|
|
217
217
|
|
|
218
218
|
| (Collection(m), Js.Json.JSONArray(items)) => {
|
|
219
|
-
module M = unpack(m:
|
|
219
|
+
module M = unpack(m: Deserializer)
|
|
220
220
|
items
|
|
221
221
|
->Array.map(M.fromJSON)
|
|
222
222
|
->Array.map(Result.warn)
|
|
@@ -226,7 +226,7 @@ module Field = {
|
|
|
226
226
|
}
|
|
227
227
|
|
|
228
228
|
| (Deserializer(m), _) => {
|
|
229
|
-
module M = unpack(m:
|
|
229
|
+
module M = unpack(m: Deserializer)
|
|
230
230
|
switch untagged->M.fromJSON {
|
|
231
231
|
| Ok(res) => res->FieldValue.any
|
|
232
232
|
| Error(msg) => raise(TypeError(msg))
|
|
@@ -253,7 +253,7 @@ module type Serializable = {
|
|
|
253
253
|
let fields: Field.t
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
-
module
|
|
256
|
+
module MakeDeserializer = (S: Serializable): (Deserializer with type t = S.t) => {
|
|
257
257
|
type t = S.t
|
|
258
258
|
let fields = S.fields
|
|
259
259
|
%%private(let (loc, _f) = __LOC_OF__(module(S: Serializable)))
|
|
@@ -269,24 +269,3 @@ module Deserializer = (S: Serializable) => {
|
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
271
|
}
|
|
272
|
-
|
|
273
|
-
module Test = {
|
|
274
|
-
type appointment = {
|
|
275
|
-
note: string,
|
|
276
|
-
date: Js.Date.t,
|
|
277
|
-
}
|
|
278
|
-
module Appointment = Deserializer({
|
|
279
|
-
type t = appointment
|
|
280
|
-
open Field
|
|
281
|
-
|
|
282
|
-
let fields = Object([("note", String), ("date", Date)])
|
|
283
|
-
})
|
|
284
|
-
|
|
285
|
-
type foo = array<appointment>
|
|
286
|
-
module Foo = Deserializer({
|
|
287
|
-
type t = foo
|
|
288
|
-
open Field
|
|
289
|
-
|
|
290
|
-
let fields = DefaultWhenInvalid(Array(Deserializer(module(Appointment))), []->FieldValue.array)
|
|
291
|
-
})
|
|
292
|
-
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
open JSON
|
|
2
|
+
|
|
3
|
+
module Test = {
|
|
4
|
+
type appointment = {
|
|
5
|
+
note: string,
|
|
6
|
+
date: Js.Date.t,
|
|
7
|
+
}
|
|
8
|
+
module Appointment = MakeDeserializer({
|
|
9
|
+
type t = appointment
|
|
10
|
+
open JSON.Field
|
|
11
|
+
|
|
12
|
+
let fields = Object([("note", String), ("date", Date)])
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
type foo = array<appointment>
|
|
16
|
+
module Foo = MakeDeserializer({
|
|
17
|
+
type t = foo
|
|
18
|
+
open JSON.Field
|
|
19
|
+
|
|
20
|
+
let fields = DefaultWhenInvalid(Array(Deserializer(module(Appointment))), []->FieldValue.array)
|
|
21
|
+
})
|
|
22
|
+
}
|