@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 CHANGED
@@ -9,7 +9,10 @@ compile: yarn.lock
9
9
  format: yarn.lock
10
10
  rescript format -all
11
11
 
12
- .PHONY: compile format
12
+ publish: compile
13
+ yarn publish --access public
14
+
15
+ .PHONY: format compile publish
13
16
 
14
17
  RESCRIPT_FILES := $(shell find src -type f -name '*.res')
15
18
 
package/README.md CHANGED
@@ -25,7 +25,7 @@ module MyData = {
25
25
  }
26
26
  }
27
27
 
28
- module MyDataDeserializer = JSON.Deserializer({
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
- This creates a function `MyDataDeserializer.fromJSON` with
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
@@ -1,9 +1,13 @@
1
1
  {
2
- "name": "rescript-deser",
2
+ "name": "@kaiko.io/rescript-deser",
3
3
  "sources": [
4
4
  {
5
5
  "dir": "src/",
6
6
  "subdirs": true
7
+ },
8
+ {
9
+ "dir": "tests",
10
+ "type": "dev"
7
11
  }
8
12
  ],
9
13
  "suffix": ".js",
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "@kaiko.io/rescript-deser",
3
- "version": "1.0.0",
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/bs-deser.git",
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 BuiltDeserializer = {
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(BuiltDeserializer))
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(BuiltDeserializer))
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: BuiltDeserializer)
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: BuiltDeserializer)
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: BuiltDeserializer)
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: BuiltDeserializer)
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 Deserializer = (S: Serializable) => {
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
+ }