@greenlabs/ppx-spice 0.1.6 → 0.1.7-rc1
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/.vscode/settings.json +6 -0
- package/CHANGELOG.md +7 -0
- package/README.md +9 -7
- package/package.json +2 -2
- package/ppx-linux.exe +0 -0
- package/ppx-osx.exe +0 -0
- package/src/ppx/codecs.ml +79 -141
- package/src/ppx/polyvariants.ml +6 -9
- package/src/ppx/records.ml +32 -11
- package/src/ppx/utils.ml +3 -1
- package/src/ppx/variants.ml +5 -9
- package/src/ppx_spice.opam +21 -0
- package/src/rescript/Spice.res +6 -1
- package/test/__tests__/test_polyvariants.js +17 -17
- package/test/__tests__/test_records.js +65 -14
- package/test/__tests__/test_records.res +60 -0
- package/test/__tests__/test_variants.js +28 -28
- package/test/package.json +1 -1
- package/test/src/Polyvariants.js +2 -1
- package/test/src/Records.js +83 -20
- package/test/src/Records.res +6 -0
- package/test/src/Records.resi +6 -0
- package/test/src/Spice.js +20 -7
- package/test/src/Variants.js +2 -1
- package/test/yarn.lock +4 -4
- package/src/ppx_spice.install +0 -43
package/CHANGELOG.md
ADDED
package/README.md
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
A ReScript PPX, which generates JSON (de)serializers.
|
|
4
4
|
|
|
5
5
|
`Spice` is originated from
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
|
|
7
|
+
- The `Spice melange` in the novel, Dune
|
|
8
|
+
- A flavor for the (polymorphic) variant
|
|
8
9
|
|
|
9
10
|
> This PPX is highly influenced by [Decco](https://github.com/reasonml-labs/decco) and developed with forking the source codes of Decco. Spice has implemented all the features of Decco@1.5.0 and additional useful features for the (polymorphic) variant of its own.
|
|
10
11
|
|
|
@@ -18,7 +19,7 @@ Whenever it is needed to parse the response in Json, the custom encoder/decoder
|
|
|
18
19
|
|
|
19
20
|
with Decco
|
|
20
21
|
|
|
21
|
-
```
|
|
22
|
+
```rescript
|
|
22
23
|
@decco
|
|
23
24
|
type status = WAITING | PROCESSING | SUCCESS | FAIL
|
|
24
25
|
|
|
@@ -54,7 +55,8 @@ type data = {
|
|
|
54
55
|
```
|
|
55
56
|
|
|
56
57
|
with Spice
|
|
57
|
-
|
|
58
|
+
|
|
59
|
+
```rescript
|
|
58
60
|
@spice
|
|
59
61
|
type status =
|
|
60
62
|
| @spice.as("waiting") WAITING
|
|
@@ -86,7 +88,7 @@ let t_encode = ...
|
|
|
86
88
|
// automatically generated
|
|
87
89
|
let t_decode = ...
|
|
88
90
|
|
|
89
|
-
let encoded = One->t_encode // Js.Json.
|
|
91
|
+
let encoded = One->t_encode // Js.Json.string(`하나`)
|
|
90
92
|
|
|
91
93
|
let decoded = Js.Json.string(`second`)->t_decode // Belt.Result.Ok(Two)
|
|
92
94
|
```
|
|
@@ -118,11 +120,11 @@ let decoded = sampleJson->Records.t_decode // Belt.Result.Ok(sampleRecord)
|
|
|
118
120
|
|
|
119
121
|
## Install
|
|
120
122
|
|
|
121
|
-
```
|
|
123
|
+
```sh
|
|
122
124
|
yarn add -D @greenlabs/ppx-spice
|
|
123
125
|
```
|
|
124
126
|
|
|
125
|
-
```
|
|
127
|
+
```json
|
|
126
128
|
// bsconfig.json
|
|
127
129
|
|
|
128
130
|
"bs-dependencies": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@greenlabs/ppx-spice",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7-rc1",
|
|
4
4
|
"description": "ReScript PPX which generate JSON (de)serializer",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Greenlabs Dev <developer@greenlabs.co.kr>",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"bugs": {
|
|
12
12
|
"url": "https://github.com/green-labs/ppx_spice/issues"
|
|
13
|
-
|
|
13
|
+
},
|
|
14
14
|
"keywords": [
|
|
15
15
|
"ReScript",
|
|
16
16
|
"ppx"
|
package/ppx-linux.exe
CHANGED
|
Binary file
|
package/ppx-osx.exe
CHANGED
|
Binary file
|
package/src/ppx/codecs.ml
CHANGED
|
@@ -27,165 +27,103 @@ and generate_constr_codecs { do_encode; do_decode }
|
|
|
27
27
|
{ Location.txt = identifier; loc } =
|
|
28
28
|
let open Longident in
|
|
29
29
|
match identifier with
|
|
30
|
-
| Lident "string" ->
|
|
31
|
-
(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
| Lident "
|
|
52
|
-
(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
match do_decode with
|
|
77
|
-
| true -> Some [%expr Spice.arrayFromJson]
|
|
78
|
-
| false -> None ))
|
|
79
|
-
| Lident "list" -> (
|
|
80
|
-
( (match do_encode with
|
|
81
|
-
| true -> Some [%expr Spice.listToJson]
|
|
82
|
-
| false -> None),
|
|
83
|
-
match do_decode with
|
|
84
|
-
| true -> Some [%expr Spice.listFromJson]
|
|
85
|
-
| false -> None ))
|
|
86
|
-
| Lident "option" -> (
|
|
87
|
-
( (match do_encode with
|
|
88
|
-
| true -> Some [%expr Spice.optionToJson]
|
|
89
|
-
| false -> None),
|
|
90
|
-
match do_decode with
|
|
91
|
-
| true -> Some [%expr Spice.optionFromJson]
|
|
92
|
-
| false -> None ))
|
|
93
|
-
| Ldot (Ldot (Lident "Belt", "Result"), "t") -> (
|
|
94
|
-
( (match do_encode with
|
|
95
|
-
| true -> Some [%expr Spice.resultToJson]
|
|
96
|
-
| false -> None),
|
|
97
|
-
match do_decode with
|
|
98
|
-
| true -> Some [%expr Spice.resultFromJson]
|
|
99
|
-
| false -> None ))
|
|
100
|
-
| Ldot (Ldot (Lident "Js", "Dict"), "t") -> (
|
|
101
|
-
( (match do_encode with
|
|
102
|
-
| true -> Some [%expr Spice.dictToJson]
|
|
103
|
-
| false -> None),
|
|
104
|
-
match do_decode with
|
|
105
|
-
| true -> Some [%expr Spice.dictFromJson]
|
|
106
|
-
| false -> None ))
|
|
107
|
-
| Ldot (Ldot (Lident "Js", "Json"), "t") -> (
|
|
108
|
-
( (match do_encode with true -> Some [%expr fun v -> v] | false -> None),
|
|
109
|
-
match do_decode with
|
|
110
|
-
| true -> Some [%expr fun v -> Belt.Result.Ok v]
|
|
111
|
-
| false -> None ))
|
|
112
|
-
| Lident s -> (
|
|
113
|
-
( (match do_encode with
|
|
114
|
-
| true -> Some (make_ident_expr (s ^ Utils.encoder_func_suffix))
|
|
115
|
-
| false -> None),
|
|
116
|
-
match do_decode with
|
|
117
|
-
| true -> Some (make_ident_expr (s ^ Utils.decoder_func_suffix))
|
|
118
|
-
| false -> None ))
|
|
119
|
-
| Ldot (left, right) -> (
|
|
120
|
-
( (match do_encode with
|
|
121
|
-
| true ->
|
|
122
|
-
Some
|
|
123
|
-
(Exp.ident
|
|
124
|
-
(mknoloc (Ldot (left, right ^ Utils.encoder_func_suffix))))
|
|
125
|
-
| false -> None),
|
|
126
|
-
match do_decode with
|
|
127
|
-
| true ->
|
|
128
|
-
Some
|
|
129
|
-
(Exp.ident
|
|
130
|
-
(mknoloc (Ldot (left, right ^ Utils.decoder_func_suffix))))
|
|
131
|
-
| false -> None ))
|
|
30
|
+
| Lident "string" ->
|
|
31
|
+
( some_if_true do_encode [%expr Spice.stringToJson],
|
|
32
|
+
some_if_true do_decode [%expr Spice.stringFromJson] )
|
|
33
|
+
| Lident "int" ->
|
|
34
|
+
( some_if_true do_encode [%expr Spice.intToJson],
|
|
35
|
+
some_if_true do_decode [%expr Spice.intFromJson] )
|
|
36
|
+
| Lident "int64" ->
|
|
37
|
+
( some_if_true do_encode [%expr Spice.int64ToJson],
|
|
38
|
+
some_if_true do_decode [%expr Spice.int64FromJson] )
|
|
39
|
+
| Lident "float" ->
|
|
40
|
+
( some_if_true do_encode [%expr Spice.floatToJson],
|
|
41
|
+
some_if_true do_decode [%expr Spice.floatFromJson] )
|
|
42
|
+
| Lident "bool" ->
|
|
43
|
+
( some_if_true do_encode [%expr Spice.boolToJson],
|
|
44
|
+
some_if_true do_decode [%expr Spice.boolFromJson] )
|
|
45
|
+
| Lident "unit" ->
|
|
46
|
+
( some_if_true do_encode [%expr Spice.unitToJson],
|
|
47
|
+
some_if_true do_decode [%expr Spice.unitFromJson] )
|
|
48
|
+
| Lident "array" ->
|
|
49
|
+
( some_if_true do_encode [%expr Spice.arrayToJson],
|
|
50
|
+
some_if_true do_decode [%expr Spice.arrayFromJson] )
|
|
51
|
+
| Lident "list" ->
|
|
52
|
+
( some_if_true do_encode [%expr Spice.listToJson],
|
|
53
|
+
some_if_true do_decode [%expr Spice.listFromJson] )
|
|
54
|
+
| Lident "option" ->
|
|
55
|
+
( some_if_true do_encode [%expr Spice.optionToJson],
|
|
56
|
+
some_if_true do_decode [%expr Spice.optionFromJson] )
|
|
57
|
+
| Ldot (Ldot (Lident "Belt", "Result"), "t") ->
|
|
58
|
+
( some_if_true do_encode [%expr Spice.resultToJson],
|
|
59
|
+
some_if_true do_decode [%expr Spice.resultFromJson] )
|
|
60
|
+
| Ldot (Ldot (Lident "Js", "Dict"), "t") ->
|
|
61
|
+
( some_if_true do_encode [%expr Spice.dictToJson],
|
|
62
|
+
some_if_true do_decode [%expr Spice.dictFromJson] )
|
|
63
|
+
| Ldot (Ldot (Lident "Js", "Json"), "t") ->
|
|
64
|
+
( some_if_true do_encode [%expr fun v -> v],
|
|
65
|
+
some_if_true do_decode [%expr fun v -> Belt.Result.Ok v] )
|
|
66
|
+
| Lident s ->
|
|
67
|
+
( some_if_true do_encode (make_ident_expr (s ^ Utils.encoder_func_suffix)),
|
|
68
|
+
some_if_true do_decode (make_ident_expr (s ^ Utils.decoder_func_suffix))
|
|
69
|
+
)
|
|
70
|
+
| Ldot (left, right) ->
|
|
71
|
+
( some_if_true do_encode
|
|
72
|
+
(Exp.ident (mknoloc (Ldot (left, right ^ Utils.encoder_func_suffix)))),
|
|
73
|
+
some_if_true do_decode
|
|
74
|
+
(Exp.ident (mknoloc (Ldot (left, right ^ Utils.decoder_func_suffix))))
|
|
75
|
+
)
|
|
132
76
|
| Lapply (_, _) -> fail loc "Lapply syntax not yet handled by spice"
|
|
133
77
|
|
|
134
|
-
and generate_codecs (
|
|
78
|
+
and generate_codecs ?(is_optional = false)
|
|
79
|
+
({ do_encode; do_decode } as generator_settings)
|
|
135
80
|
{ ptyp_desc; ptyp_loc; ptyp_attributes } =
|
|
136
81
|
match ptyp_desc with
|
|
137
82
|
| Ptyp_any -> fail ptyp_loc "Can't generate codecs for `any` type"
|
|
138
83
|
| Ptyp_arrow (_, _, _) ->
|
|
139
84
|
fail ptyp_loc "Can't generate codecs for function type"
|
|
140
85
|
| Ptyp_package _ -> fail ptyp_loc "Can't generate codecs for module type"
|
|
141
|
-
| Ptyp_tuple types ->
|
|
86
|
+
| Ptyp_tuple types ->
|
|
142
87
|
let composite_codecs =
|
|
143
|
-
List.map (generate_codecs generator_settings) types
|
|
88
|
+
List.map (generate_codecs ~is_optional generator_settings) types
|
|
144
89
|
in
|
|
145
|
-
(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|> List.map (fun (_, d) -> Option.get d)
|
|
157
|
-
|> Tuple.generate_decoder)
|
|
158
|
-
| false -> None ))
|
|
159
|
-
| Ptyp_var s -> (
|
|
160
|
-
( (match do_encode with
|
|
161
|
-
| true -> Some (make_ident_expr (encoder_var_prefix ^ s))
|
|
162
|
-
| false -> None),
|
|
163
|
-
match do_decode with
|
|
164
|
-
| true -> Some (make_ident_expr (decoder_var_prefix ^ s))
|
|
165
|
-
| false -> None ))
|
|
90
|
+
( some_if_true do_encode
|
|
91
|
+
(composite_codecs
|
|
92
|
+
|> List.map (fun (e, _) -> Option.get e)
|
|
93
|
+
|> Tuple.generate_encoder),
|
|
94
|
+
some_if_true do_decode
|
|
95
|
+
(composite_codecs
|
|
96
|
+
|> List.map (fun (_, d) -> Option.get d)
|
|
97
|
+
|> Tuple.generate_decoder) )
|
|
98
|
+
| Ptyp_var s ->
|
|
99
|
+
( some_if_true do_encode (make_ident_expr (encoder_var_prefix ^ s)),
|
|
100
|
+
some_if_true do_decode (make_ident_expr (decoder_var_prefix ^ s)) )
|
|
166
101
|
| Ptyp_constr (constr, typeArgs) -> (
|
|
167
102
|
let custom_codec = get_attribute_by_name ptyp_attributes "spice.codec" in
|
|
168
103
|
let encode, decode =
|
|
169
104
|
match custom_codec with
|
|
170
105
|
| Ok None -> generate_constr_codecs generator_settings constr
|
|
171
|
-
| Ok (Some attribute) ->
|
|
106
|
+
| Ok (Some attribute) ->
|
|
172
107
|
let expr = get_expression_from_payload attribute in
|
|
173
|
-
(
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
| true ->
|
|
182
|
-
Some
|
|
183
|
-
[%expr
|
|
184
|
-
let _, d = [%e expr] in
|
|
185
|
-
d]
|
|
186
|
-
| false -> None ))
|
|
108
|
+
( some_if_true do_encode
|
|
109
|
+
[%expr
|
|
110
|
+
let e, _ = [%e expr] in
|
|
111
|
+
e],
|
|
112
|
+
some_if_true do_decode
|
|
113
|
+
[%expr
|
|
114
|
+
let _, d = [%e expr] in
|
|
115
|
+
d] )
|
|
187
116
|
| Error s -> fail ptyp_loc s
|
|
188
117
|
in
|
|
118
|
+
let encode, decode =
|
|
119
|
+
if is_optional then
|
|
120
|
+
match (encode, decode) with
|
|
121
|
+
| Some encode, Some decode ->
|
|
122
|
+
( Some [%expr Spice.optionToJson [%e encode]],
|
|
123
|
+
Some [%expr Spice.optionFromJson [%e decode]] )
|
|
124
|
+
| _ -> (encode, decode)
|
|
125
|
+
else (encode, decode)
|
|
126
|
+
in
|
|
189
127
|
match List.length typeArgs = 0 with
|
|
190
128
|
| true -> (encode, decode)
|
|
191
129
|
| false -> parameterize_codecs typeArgs encode decode generator_settings)
|
package/src/ppx/polyvariants.ml
CHANGED
|
@@ -219,15 +219,12 @@ let generate_codecs ({ do_encode; do_decode } as generator_settings) row_fields
|
|
|
219
219
|
in
|
|
220
220
|
|
|
221
221
|
let encoder =
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|> Exp.fun_ Asttypes.Nolabel None [%pat? v]
|
|
229
|
-
|> Option.some
|
|
230
|
-
| false -> None
|
|
222
|
+
some_if_true do_encode
|
|
223
|
+
(List.map
|
|
224
|
+
(generate_encoder_case generator_settings unboxed has_attr_as)
|
|
225
|
+
parsed_fields
|
|
226
|
+
|> Exp.match_ [%expr v]
|
|
227
|
+
|> Exp.fun_ Asttypes.Nolabel None [%pat? v])
|
|
231
228
|
in
|
|
232
229
|
|
|
233
230
|
let decoder =
|
package/src/ppx/records.ml
CHANGED
|
@@ -11,8 +11,16 @@ type parsed_decl = {
|
|
|
11
11
|
field : expression;
|
|
12
12
|
codecs : expression option * expression option;
|
|
13
13
|
default : expression option;
|
|
14
|
+
is_optional : bool;
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
let optional_attr : Ppxlib.Parsetree.attribute =
|
|
18
|
+
{
|
|
19
|
+
attr_name = { txt = "ns.optional"; loc = Location.none };
|
|
20
|
+
attr_payload = PStr [];
|
|
21
|
+
attr_loc = Location.none;
|
|
22
|
+
}
|
|
23
|
+
|
|
16
24
|
let generate_encoder decls unboxed =
|
|
17
25
|
match unboxed with
|
|
18
26
|
| true ->
|
|
@@ -22,11 +30,17 @@ let generate_encoder decls unboxed =
|
|
|
22
30
|
| false ->
|
|
23
31
|
let arrExpr =
|
|
24
32
|
decls
|
|
25
|
-
|> List.map (fun { key; field; codecs = encoder, _ } ->
|
|
26
|
-
|
|
33
|
+
|> List.map (fun { key; field; codecs = encoder, _; is_optional } ->
|
|
34
|
+
let is_optional =
|
|
35
|
+
if is_optional then [%expr true] else [%expr false]
|
|
36
|
+
in
|
|
37
|
+
[%expr
|
|
38
|
+
[%e key], [%e is_optional], [%e Option.get encoder] [%e field]])
|
|
27
39
|
|> Exp.array
|
|
28
40
|
in
|
|
29
|
-
[%expr
|
|
41
|
+
[%expr
|
|
42
|
+
[%e arrExpr] |> Spice.filterOptional |> Js.Dict.fromArray
|
|
43
|
+
|> Js.Json.object_]
|
|
30
44
|
|> Exp.fun_ Asttypes.Nolabel None [%pat? v]
|
|
31
45
|
|
|
32
46
|
let generate_dict_get { key; codecs = _, decoder; default } =
|
|
@@ -53,7 +67,10 @@ let generate_error_case { key } =
|
|
|
53
67
|
}
|
|
54
68
|
|
|
55
69
|
let generate_final_record_expr decls =
|
|
56
|
-
decls
|
|
70
|
+
decls
|
|
71
|
+
|> List.map (fun { name; is_optional } ->
|
|
72
|
+
let attrs = if is_optional then [ optional_attr ] else [] in
|
|
73
|
+
(lid name, make_ident_expr ~attrs name))
|
|
57
74
|
|> fun l -> [%expr Belt.Result.Ok [%e Exp.record l None]]
|
|
58
75
|
|
|
59
76
|
let generate_success_case { name } success_expr =
|
|
@@ -113,20 +130,24 @@ let parse_decl generator_settings
|
|
|
113
130
|
| Ok None -> Exp.constant (Pconst_string (txt, Location.none, None))
|
|
114
131
|
| Error s -> fail pld_loc s
|
|
115
132
|
in
|
|
133
|
+
let optional_attrs = [ "ns.optional"; "res.optional" ] in
|
|
134
|
+
let is_optional =
|
|
135
|
+
optional_attrs
|
|
136
|
+
|> List.map (fun attr -> get_attribute_by_name pld_attributes attr)
|
|
137
|
+
|> List.exists (function Ok (Some _) -> true | _ -> false)
|
|
138
|
+
in
|
|
139
|
+
|
|
116
140
|
{
|
|
117
141
|
name = txt;
|
|
118
142
|
key;
|
|
119
143
|
field = Exp.field [%expr v] (lid txt);
|
|
120
|
-
codecs = Codecs.generate_codecs generator_settings pld_type;
|
|
144
|
+
codecs = Codecs.generate_codecs ~is_optional generator_settings pld_type;
|
|
121
145
|
default;
|
|
146
|
+
is_optional;
|
|
122
147
|
}
|
|
123
148
|
|
|
124
149
|
let generate_codecs ({ do_encode; do_decode } as generator_settings) decls
|
|
125
150
|
unboxed =
|
|
126
151
|
let parsed_decls = List.map (parse_decl generator_settings) decls in
|
|
127
|
-
(
|
|
128
|
-
|
|
129
|
-
| false -> None),
|
|
130
|
-
match do_decode with
|
|
131
|
-
| true -> Some (generate_decoder parsed_decls unboxed)
|
|
132
|
-
| false -> None )
|
|
152
|
+
( some_if_true do_encode (generate_encoder parsed_decls unboxed),
|
|
153
|
+
some_if_true do_decode (generate_decoder parsed_decls unboxed) )
|
package/src/ppx/utils.ml
CHANGED
|
@@ -24,7 +24,7 @@ let mknoloc txt = mkloc txt Location.none
|
|
|
24
24
|
|
|
25
25
|
let lid ?(loc = Location.none) s = mkloc (Longident.parse s) loc
|
|
26
26
|
|
|
27
|
-
let make_ident_expr s = Exp.ident (mknoloc (longident_parse s))
|
|
27
|
+
let make_ident_expr ?attrs s = Exp.ident ?attrs (mknoloc (longident_parse s))
|
|
28
28
|
|
|
29
29
|
let tuple_or_singleton tuple l =
|
|
30
30
|
match List.length l > 1 with true -> tuple l | false -> List.hd l
|
|
@@ -113,3 +113,5 @@ let attr_warning expr =
|
|
|
113
113
|
attr_payload = PStr [ { pstr_desc = Pstr_eval (expr, []); pstr_loc = loc } ];
|
|
114
114
|
attr_loc = loc;
|
|
115
115
|
}
|
|
116
|
+
|
|
117
|
+
let some_if_true cond a = match cond with true -> Some a | false -> None
|
package/src/ppx/variants.ml
CHANGED
|
@@ -188,15 +188,11 @@ let generate_codecs ({ do_encode; do_decode } as generator_settings)
|
|
|
188
188
|
in
|
|
189
189
|
|
|
190
190
|
let encoder =
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|> Exp.match_ [%expr v]
|
|
197
|
-
|> Exp.fun_ Asttypes.Nolabel None [%pat? v]
|
|
198
|
-
|> Option.some
|
|
199
|
-
| false -> None
|
|
191
|
+
some_if_true do_encode
|
|
192
|
+
(parsed_decls
|
|
193
|
+
|> List.map (generate_encoder_case generator_settings unboxed has_attr_as)
|
|
194
|
+
|> Exp.match_ [%expr v]
|
|
195
|
+
|> Exp.fun_ Asttypes.Nolabel None [%pat? v])
|
|
200
196
|
in
|
|
201
197
|
|
|
202
198
|
let decoder =
|
package/src/ppx_spice.opam
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
opam-version: "2.0"
|
|
2
|
+
name: "ppx_spice"
|
|
3
|
+
version: "0.1.7"
|
|
4
|
+
synopsis: "ReScript PPX which generate JSON (de)serializer"
|
|
5
|
+
description: """
|
|
6
|
+
ReScript PPX which generate JSON (de)serializer
|
|
7
|
+
"""
|
|
8
|
+
maintainer: "Greenlabs Dev <developer@greenlabs.co.kr>"
|
|
9
|
+
authors: "Greenlabs Dev <developer@greenlabs.co.kr>"
|
|
10
|
+
license: "MIT"
|
|
11
|
+
homepage: "https://github.com/green-labs/ppx_spice"
|
|
12
|
+
bug-reports: "https://github.com/green-labs/ppx_spice/issues"
|
|
13
|
+
dev-repo: "git+https://github.com/green-labs/ppx_spice.git"
|
|
14
|
+
depends: [
|
|
15
|
+
"ocaml" {"4.12.1"}
|
|
16
|
+
"dune" { >= "2.7"}
|
|
17
|
+
"ppxlib" {"0.23.0"}
|
|
18
|
+
]
|
|
19
|
+
build: [
|
|
20
|
+
["dune" "build" "-p" name "-j" jobs]
|
|
21
|
+
]
|
package/src/rescript/Spice.res
CHANGED
|
@@ -14,7 +14,7 @@ let error = (~path=?, message, value) => {
|
|
|
14
14
|
| None => ""
|
|
15
15
|
| Some(s) => s
|
|
16
16
|
}
|
|
17
|
-
Belt.Result.Error({path
|
|
17
|
+
Belt.Result.Error({path, message, value})
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
let stringToJson = s => Js.Json.string(s)
|
|
@@ -98,6 +98,11 @@ let optionToJson = (encoder, opt) =>
|
|
|
98
98
|
| None => Js.Json.null
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
let filterOptional = arr =>
|
|
102
|
+
arr
|
|
103
|
+
|> Belt.Array.keep(_, ((_, isOptional, x)) => !(isOptional && x == Js.Json.null))
|
|
104
|
+
|> Belt.Array.map(_, ((k, _, v)) => (k, v))
|
|
105
|
+
|
|
101
106
|
let optionFromJson = (decoder, json) =>
|
|
102
107
|
switch Js.Json.decodeNull(json) {
|
|
103
108
|
| Some(_) => Belt.Result.Ok(None)
|
|
@@ -5,28 +5,28 @@ var Jest = require("@glennsl/bs-jest/src/jest.js");
|
|
|
5
5
|
var Polyvariants = require("../src/Polyvariants.js");
|
|
6
6
|
|
|
7
7
|
Jest.describe("polymorphic variants with attribute", (function (param) {
|
|
8
|
-
Jest.test("encode
|
|
8
|
+
Jest.test("encode 하나", (function (param) {
|
|
9
9
|
var polyvariantEncoded = Polyvariants.t_encode("one");
|
|
10
10
|
return Jest.Expect.toEqual("하나", Jest.Expect.expect(polyvariantEncoded));
|
|
11
11
|
}));
|
|
12
|
-
Jest.test("encode
|
|
12
|
+
Jest.test("encode 둘", (function (param) {
|
|
13
13
|
var polyvariantEncoded = Polyvariants.t_encode("two");
|
|
14
14
|
return Jest.Expect.toEqual("둘", Jest.Expect.expect(polyvariantEncoded));
|
|
15
15
|
}));
|
|
16
|
-
Jest.test("decode
|
|
16
|
+
Jest.test("decode 하나", (function (param) {
|
|
17
17
|
var polyvariantDecoded = Polyvariants.t_decode("하나");
|
|
18
18
|
return Jest.Expect.toEqual({
|
|
19
19
|
TAG: /* Ok */0,
|
|
20
20
|
_0: "one"
|
|
21
21
|
}, Jest.Expect.expect(polyvariantDecoded));
|
|
22
22
|
}));
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
Jest.test("decode 둘", (function (param) {
|
|
24
|
+
var polyvariantDecoded = Polyvariants.t_decode("둘");
|
|
25
|
+
return Jest.Expect.toEqual({
|
|
26
|
+
TAG: /* Ok */0,
|
|
27
|
+
_0: "two"
|
|
28
|
+
}, Jest.Expect.expect(polyvariantDecoded));
|
|
29
|
+
}));
|
|
30
30
|
}));
|
|
31
31
|
|
|
32
32
|
Jest.describe("polymorphic variants", (function (param) {
|
|
@@ -45,13 +45,13 @@ Jest.describe("polymorphic variants", (function (param) {
|
|
|
45
45
|
_0: "one"
|
|
46
46
|
}, Jest.Expect.expect(polyvariantDecoded));
|
|
47
47
|
}));
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
Jest.test("decode two", (function (param) {
|
|
49
|
+
var polyvariantDecoded = Polyvariants.t1_decode(["two"]);
|
|
50
|
+
return Jest.Expect.toEqual({
|
|
51
|
+
TAG: /* Ok */0,
|
|
52
|
+
_0: "two"
|
|
53
|
+
}, Jest.Expect.expect(polyvariantDecoded));
|
|
54
|
+
}));
|
|
55
55
|
}));
|
|
56
56
|
|
|
57
57
|
/* Not a pure module */
|
|
@@ -16,13 +16,13 @@ Jest.describe("record with @spice.key", (function (param) {
|
|
|
16
16
|
var encoded = Records.t_encode(sampleRecord);
|
|
17
17
|
return Jest.Expect.toEqual(sample, Jest.Expect.expect(encoded));
|
|
18
18
|
}));
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
Jest.test("decode", (function (param) {
|
|
20
|
+
var decoded = Records.t_decode(sample);
|
|
21
|
+
return Jest.Expect.toEqual({
|
|
22
|
+
TAG: /* Ok */0,
|
|
23
|
+
_0: sampleRecord
|
|
24
|
+
}, Jest.Expect.expect(decoded));
|
|
25
|
+
}));
|
|
26
26
|
}));
|
|
27
27
|
|
|
28
28
|
Jest.describe("record without @spice.key", (function (param) {
|
|
@@ -37,13 +37,64 @@ Jest.describe("record without @spice.key", (function (param) {
|
|
|
37
37
|
var encoded = Records.t1_encode(sampleRecord);
|
|
38
38
|
return Jest.Expect.toEqual(sample, Jest.Expect.expect(encoded));
|
|
39
39
|
}));
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
Jest.test("decode", (function (param) {
|
|
41
|
+
var decoded = Records.t1_decode(sample);
|
|
42
|
+
return Jest.Expect.toEqual({
|
|
43
|
+
TAG: /* Ok */0,
|
|
44
|
+
_0: sampleRecord
|
|
45
|
+
}, Jest.Expect.expect(decoded));
|
|
46
|
+
}));
|
|
47
|
+
}));
|
|
48
|
+
|
|
49
|
+
Jest.describe("record with optional field", (function (param) {
|
|
50
|
+
var sample1 = {};
|
|
51
|
+
sample1["label"] = "sample";
|
|
52
|
+
sample1["value"] = 1.0;
|
|
53
|
+
var sampleRecord1 = {
|
|
54
|
+
label: "sample",
|
|
55
|
+
value: 1
|
|
56
|
+
};
|
|
57
|
+
Jest.test("encode", (function (param) {
|
|
58
|
+
var encoded = Records.tOp_encode(sampleRecord1);
|
|
59
|
+
return Jest.Expect.toEqual(sample1, Jest.Expect.expect(encoded));
|
|
60
|
+
}));
|
|
61
|
+
Jest.test("decode", (function (param) {
|
|
62
|
+
var decoded = Records.tOp_decode(sample1);
|
|
63
|
+
return Jest.Expect.toEqual({
|
|
64
|
+
TAG: /* Ok */0,
|
|
65
|
+
_0: sampleRecord1
|
|
66
|
+
}, Jest.Expect.expect(decoded));
|
|
67
|
+
}));
|
|
68
|
+
var sample2 = {};
|
|
69
|
+
sample2["label"] = "sample";
|
|
70
|
+
var sampleRecord2 = {
|
|
71
|
+
label: "sample"
|
|
72
|
+
};
|
|
73
|
+
Jest.test("encode omit optional field", (function (param) {
|
|
74
|
+
var encoded = Records.tOp_encode(sampleRecord2);
|
|
75
|
+
return Jest.Expect.toEqual(sample2, Jest.Expect.expect(encoded));
|
|
76
|
+
}));
|
|
77
|
+
Jest.test("decode omit optional field", (function (param) {
|
|
78
|
+
var decoded = Records.tOp_decode(sample2);
|
|
79
|
+
return Jest.Expect.toEqual({
|
|
80
|
+
TAG: /* Ok */0,
|
|
81
|
+
_0: sampleRecord2
|
|
82
|
+
}, Jest.Expect.expect(decoded));
|
|
83
|
+
}));
|
|
84
|
+
var sample3 = {};
|
|
85
|
+
sample3["label"] = null;
|
|
86
|
+
var sampleRecord3 = {};
|
|
87
|
+
Jest.test("encode omit optional field with None field", (function (param) {
|
|
88
|
+
var encoded = Records.tOp_encode(sampleRecord3);
|
|
89
|
+
return Jest.Expect.toEqual(sample3, Jest.Expect.expect(encoded));
|
|
90
|
+
}));
|
|
91
|
+
Jest.test("decode omit optional field with None field", (function (param) {
|
|
92
|
+
var decoded = Records.tOp_decode(sample3);
|
|
93
|
+
return Jest.Expect.toEqual({
|
|
94
|
+
TAG: /* Ok */0,
|
|
95
|
+
_0: sampleRecord3
|
|
96
|
+
}, Jest.Expect.expect(decoded));
|
|
97
|
+
}));
|
|
47
98
|
}));
|
|
48
99
|
|
|
49
100
|
/* Not a pure module */
|
|
@@ -49,3 +49,63 @@ describe("record without @spice.key", _ => {
|
|
|
49
49
|
expect(decoded) |> toEqual(Belt.Result.Ok(sampleRecord))
|
|
50
50
|
})
|
|
51
51
|
})
|
|
52
|
+
|
|
53
|
+
describe("record with optional field", _ => {
|
|
54
|
+
open Records
|
|
55
|
+
|
|
56
|
+
let sample1 = Js.Dict.empty()
|
|
57
|
+
sample1->Js.Dict.set("label", Js.Json.string("sample"))
|
|
58
|
+
sample1->Js.Dict.set("value", Js.Json.number(1.0))
|
|
59
|
+
let sampleJson1 = sample1->Js.Json.object_
|
|
60
|
+
|
|
61
|
+
let sampleRecord1: tOp = {
|
|
62
|
+
label: Some("sample"),
|
|
63
|
+
value: 1,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
test(`encode`, _ => {
|
|
67
|
+
let encoded = sampleRecord1->tOp_encode
|
|
68
|
+
expect(encoded) |> toEqual(sampleJson1)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test(`decode`, _ => {
|
|
72
|
+
let decoded = sampleJson1->Records.tOp_decode
|
|
73
|
+
expect(decoded) |> toEqual(Belt.Result.Ok(sampleRecord1))
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
let sample2 = Js.Dict.empty()
|
|
77
|
+
sample2->Js.Dict.set("label", Js.Json.string("sample"))
|
|
78
|
+
let sampleJson2 = sample2->Js.Json.object_
|
|
79
|
+
|
|
80
|
+
let sampleRecord2: tOp = {
|
|
81
|
+
label: Some("sample"),
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
test(`encode omit optional field`, _ => {
|
|
85
|
+
let encoded = sampleRecord2->tOp_encode
|
|
86
|
+
expect(encoded) |> toEqual(sampleJson2)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
test(`decode omit optional field`, _ => {
|
|
90
|
+
let decoded = sampleJson2->Records.tOp_decode
|
|
91
|
+
expect(decoded) |> toEqual(Belt.Result.Ok(sampleRecord2))
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
let sample3 = Js.Dict.empty()
|
|
95
|
+
sample3->Js.Dict.set("label", Js.Json.null)
|
|
96
|
+
let sampleJson3 = sample3->Js.Json.object_
|
|
97
|
+
|
|
98
|
+
let sampleRecord3: tOp = {
|
|
99
|
+
label: None,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
test(`encode omit optional field with None field`, _ => {
|
|
103
|
+
let encoded = sampleRecord3->tOp_encode
|
|
104
|
+
expect(encoded) |> toEqual(sampleJson3)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
test(`decode omit optional field with None field`, _ => {
|
|
108
|
+
let decoded = sampleJson3->Records.tOp_decode
|
|
109
|
+
expect(decoded) |> toEqual(Belt.Result.Ok(sampleRecord3))
|
|
110
|
+
})
|
|
111
|
+
})
|
|
@@ -20,13 +20,13 @@ Jest.describe("variants with @spice.as", (function (param) {
|
|
|
20
20
|
_0: /* One */0
|
|
21
21
|
}, Jest.Expect.expect(variantDecoded));
|
|
22
22
|
}));
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
Jest.test("decode 둘", (function (param) {
|
|
24
|
+
var variantDecoded = Variants.t_decode("둘");
|
|
25
|
+
return Jest.Expect.toEqual({
|
|
26
|
+
TAG: /* Ok */0,
|
|
27
|
+
_0: /* Two */1
|
|
28
|
+
}, Jest.Expect.expect(variantDecoded));
|
|
29
|
+
}));
|
|
30
30
|
}));
|
|
31
31
|
|
|
32
32
|
Jest.describe("variants without @spice.as", (function (param) {
|
|
@@ -45,13 +45,13 @@ Jest.describe("variants without @spice.as", (function (param) {
|
|
|
45
45
|
_0: /* One1 */0
|
|
46
46
|
}, Jest.Expect.expect(variantDecoded));
|
|
47
47
|
}));
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
Jest.test("decode [\"Two1\"]", (function (param) {
|
|
49
|
+
var variantDecoded = Variants.t1_decode(["Two1"]);
|
|
50
|
+
return Jest.Expect.toEqual({
|
|
51
|
+
TAG: /* Ok */0,
|
|
52
|
+
_0: /* Two1 */1
|
|
53
|
+
}, Jest.Expect.expect(variantDecoded));
|
|
54
|
+
}));
|
|
55
55
|
}));
|
|
56
56
|
|
|
57
57
|
Jest.describe("unboxed variants with @spice.as", (function (param) {
|
|
@@ -59,13 +59,13 @@ Jest.describe("unboxed variants with @spice.as", (function (param) {
|
|
|
59
59
|
var variantEncoded = Variants.t2_encode(0);
|
|
60
60
|
return Jest.Expect.toEqual(0.0, Jest.Expect.expect(variantEncoded));
|
|
61
61
|
}));
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
Jest.test("decode 하나", (function (param) {
|
|
63
|
+
var variantDecoded = Variants.t2_decode(0.0);
|
|
64
|
+
return Jest.Expect.toEqual({
|
|
65
|
+
TAG: /* Ok */0,
|
|
66
|
+
_0: 0
|
|
67
|
+
}, Jest.Expect.expect(variantDecoded));
|
|
68
|
+
}));
|
|
69
69
|
}));
|
|
70
70
|
|
|
71
71
|
Jest.describe("unboxed variants without @spice.as", (function (param) {
|
|
@@ -73,13 +73,13 @@ Jest.describe("unboxed variants without @spice.as", (function (param) {
|
|
|
73
73
|
var variantEncoded = Variants.t3_encode(0);
|
|
74
74
|
return Jest.Expect.toEqual(0.0, Jest.Expect.expect(variantEncoded));
|
|
75
75
|
}));
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
76
|
+
Jest.test("decode 0", (function (param) {
|
|
77
|
+
var variantDecoded = Variants.t3_decode(0.0);
|
|
78
|
+
return Jest.Expect.toEqual({
|
|
79
|
+
TAG: /* Ok */0,
|
|
80
|
+
_0: 0
|
|
81
|
+
}, Jest.Expect.expect(variantDecoded));
|
|
82
|
+
}));
|
|
83
83
|
}));
|
|
84
84
|
|
|
85
85
|
/* Not a pure module */
|
package/test/package.json
CHANGED
package/test/src/Polyvariants.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
var Spice = require("./Spice.js");
|
|
5
5
|
var Js_json = require("rescript/lib/js/js_json.js");
|
|
6
|
+
var Js_array = require("rescript/lib/js/js_array.js");
|
|
6
7
|
var Belt_Array = require("rescript/lib/js/belt_Array.js");
|
|
7
8
|
|
|
8
9
|
function t_encode(v) {
|
|
@@ -57,7 +58,7 @@ function t1_decode(v) {
|
|
|
57
58
|
if (json_arr$1.length === 0) {
|
|
58
59
|
return Spice.error(undefined, "Expected polyvariant, found empty array", v);
|
|
59
60
|
}
|
|
60
|
-
var tagged =
|
|
61
|
+
var tagged = Js_array.map(Js_json.classify, json_arr$1);
|
|
61
62
|
var match = Belt_Array.getExn(tagged, 0);
|
|
62
63
|
if (typeof match !== "number" && match.TAG === /* JSONString */0) {
|
|
63
64
|
switch (match._0) {
|
package/test/src/Records.js
CHANGED
|
@@ -7,16 +7,18 @@ var Js_json = require("rescript/lib/js/js_json.js");
|
|
|
7
7
|
var Belt_Option = require("rescript/lib/js/belt_Option.js");
|
|
8
8
|
|
|
9
9
|
function t_encode(v) {
|
|
10
|
-
return Js_dict.fromArray([
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
return Js_dict.fromArray(Spice.filterOptional([
|
|
11
|
+
[
|
|
12
|
+
"spice-label",
|
|
13
|
+
false,
|
|
14
|
+
Spice.stringToJson(v.label)
|
|
15
|
+
],
|
|
16
|
+
[
|
|
17
|
+
"spice-value",
|
|
18
|
+
false,
|
|
19
|
+
Spice.intToJson(v.value)
|
|
20
|
+
]
|
|
21
|
+
]));
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
function t_decode(v) {
|
|
@@ -62,16 +64,18 @@ function t_decode(v) {
|
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
function t1_encode(v) {
|
|
65
|
-
return Js_dict.fromArray([
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
67
|
+
return Js_dict.fromArray(Spice.filterOptional([
|
|
68
|
+
[
|
|
69
|
+
"label",
|
|
70
|
+
false,
|
|
71
|
+
Spice.stringToJson(v.label)
|
|
72
|
+
],
|
|
73
|
+
[
|
|
74
|
+
"value",
|
|
75
|
+
false,
|
|
76
|
+
Spice.intToJson(v.value)
|
|
77
|
+
]
|
|
78
|
+
]));
|
|
75
79
|
}
|
|
76
80
|
|
|
77
81
|
function t1_decode(v) {
|
|
@@ -116,8 +120,67 @@ function t1_decode(v) {
|
|
|
116
120
|
};
|
|
117
121
|
}
|
|
118
122
|
|
|
123
|
+
function tOp_encode(v) {
|
|
124
|
+
return Js_dict.fromArray(Spice.filterOptional([
|
|
125
|
+
[
|
|
126
|
+
"label",
|
|
127
|
+
false,
|
|
128
|
+
Spice.optionToJson(Spice.stringToJson, v.label)
|
|
129
|
+
],
|
|
130
|
+
[
|
|
131
|
+
"value",
|
|
132
|
+
true,
|
|
133
|
+
Spice.optionToJson(Spice.intToJson, v.value)
|
|
134
|
+
]
|
|
135
|
+
]));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function tOp_decode(v) {
|
|
139
|
+
var dict = Js_json.classify(v);
|
|
140
|
+
if (typeof dict === "number") {
|
|
141
|
+
return Spice.error(undefined, "Not an object", v);
|
|
142
|
+
}
|
|
143
|
+
if (dict.TAG !== /* JSONObject */2) {
|
|
144
|
+
return Spice.error(undefined, "Not an object", v);
|
|
145
|
+
}
|
|
146
|
+
var dict$1 = dict._0;
|
|
147
|
+
var label = Spice.optionFromJson(Spice.stringFromJson, Belt_Option.getWithDefault(Js_dict.get(dict$1, "label"), null));
|
|
148
|
+
if (label.TAG === /* Ok */0) {
|
|
149
|
+
var value = Spice.optionFromJson(Spice.intFromJson, Belt_Option.getWithDefault(Js_dict.get(dict$1, "value"), null));
|
|
150
|
+
if (value.TAG === /* Ok */0) {
|
|
151
|
+
return {
|
|
152
|
+
TAG: /* Ok */0,
|
|
153
|
+
_0: {
|
|
154
|
+
label: label._0,
|
|
155
|
+
value: value._0
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
var e = value._0;
|
|
160
|
+
return {
|
|
161
|
+
TAG: /* Error */1,
|
|
162
|
+
_0: {
|
|
163
|
+
path: ".value" + e.path,
|
|
164
|
+
message: e.message,
|
|
165
|
+
value: e.value
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
var e$1 = label._0;
|
|
170
|
+
return {
|
|
171
|
+
TAG: /* Error */1,
|
|
172
|
+
_0: {
|
|
173
|
+
path: ".label" + e$1.path,
|
|
174
|
+
message: e$1.message,
|
|
175
|
+
value: e$1.value
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
119
180
|
exports.t_encode = t_encode;
|
|
120
181
|
exports.t_decode = t_decode;
|
|
121
182
|
exports.t1_encode = t1_encode;
|
|
122
183
|
exports.t1_decode = t1_decode;
|
|
184
|
+
exports.tOp_encode = tOp_encode;
|
|
185
|
+
exports.tOp_decode = tOp_decode;
|
|
123
186
|
/* No side effect */
|
package/test/src/Records.res
CHANGED
package/test/src/Records.resi
CHANGED
package/test/src/Spice.js
CHANGED
|
@@ -6,6 +6,8 @@ var Curry = require("rescript/lib/js/curry.js");
|
|
|
6
6
|
var Js_dict = require("rescript/lib/js/js_dict.js");
|
|
7
7
|
var Js_json = require("rescript/lib/js/js_json.js");
|
|
8
8
|
var Js_math = require("rescript/lib/js/js_math.js");
|
|
9
|
+
var Caml_obj = require("rescript/lib/js/caml_obj.js");
|
|
10
|
+
var Js_array = require("rescript/lib/js/js_array.js");
|
|
9
11
|
var Belt_Array = require("rescript/lib/js/belt_Array.js");
|
|
10
12
|
var Caml_int64 = require("rescript/lib/js/caml_int64.js");
|
|
11
13
|
var Belt_Result = require("rescript/lib/js/belt_Result.js");
|
|
@@ -166,14 +168,12 @@ function unitFromJson(param) {
|
|
|
166
168
|
};
|
|
167
169
|
}
|
|
168
170
|
|
|
169
|
-
|
|
170
|
-
return arr.map(Curry.__1(encoder));
|
|
171
|
-
}
|
|
171
|
+
var arrayToJson = Js_array.map;
|
|
172
172
|
|
|
173
173
|
function arrayFromJson(decoder, json) {
|
|
174
174
|
var arr = Js_json.decodeArray(json);
|
|
175
175
|
if (arr !== undefined) {
|
|
176
|
-
return
|
|
176
|
+
return Js_array.reducei((function (acc, jsonI, i) {
|
|
177
177
|
var match = Curry._1(decoder, jsonI);
|
|
178
178
|
if (acc.TAG !== /* Ok */0) {
|
|
179
179
|
return acc;
|
|
@@ -181,7 +181,7 @@ function arrayFromJson(decoder, json) {
|
|
|
181
181
|
if (match.TAG === /* Ok */0) {
|
|
182
182
|
return {
|
|
183
183
|
TAG: /* Ok */0,
|
|
184
|
-
_0:
|
|
184
|
+
_0: Js_array.concat([match._0], acc._0)
|
|
185
185
|
};
|
|
186
186
|
}
|
|
187
187
|
var error = match._0;
|
|
@@ -196,7 +196,7 @@ function arrayFromJson(decoder, json) {
|
|
|
196
196
|
}), {
|
|
197
197
|
TAG: /* Ok */0,
|
|
198
198
|
_0: []
|
|
199
|
-
});
|
|
199
|
+
}, arr);
|
|
200
200
|
} else {
|
|
201
201
|
return {
|
|
202
202
|
TAG: /* Error */1,
|
|
@@ -211,7 +211,7 @@ function arrayFromJson(decoder, json) {
|
|
|
211
211
|
|
|
212
212
|
function listToJson(encoder, list) {
|
|
213
213
|
var arr = $$Array.of_list(list);
|
|
214
|
-
return
|
|
214
|
+
return Js_array.map(encoder, arr);
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
function listFromJson(decoder, json) {
|
|
@@ -227,6 +227,18 @@ function optionToJson(encoder, opt) {
|
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
+
function filterOptional(arr) {
|
|
231
|
+
var __x = Belt_Array.keep(arr, (function (param) {
|
|
232
|
+
return !(param[1] && Caml_obj.equal(param[2], null));
|
|
233
|
+
}));
|
|
234
|
+
return Belt_Array.map(__x, (function (param) {
|
|
235
|
+
return [
|
|
236
|
+
param[0],
|
|
237
|
+
param[2]
|
|
238
|
+
];
|
|
239
|
+
}));
|
|
240
|
+
}
|
|
241
|
+
|
|
230
242
|
function optionFromJson(decoder, json) {
|
|
231
243
|
var match = Js_json.decodeNull(json);
|
|
232
244
|
if (match !== undefined) {
|
|
@@ -426,6 +438,7 @@ exports.arrayFromJson = arrayFromJson;
|
|
|
426
438
|
exports.listToJson = listToJson;
|
|
427
439
|
exports.listFromJson = listFromJson;
|
|
428
440
|
exports.optionToJson = optionToJson;
|
|
441
|
+
exports.filterOptional = filterOptional;
|
|
429
442
|
exports.optionFromJson = optionFromJson;
|
|
430
443
|
exports.resultToJson = resultToJson;
|
|
431
444
|
exports.resultFromJson = resultFromJson;
|
package/test/src/Variants.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
var Spice = require("./Spice.js");
|
|
5
5
|
var Js_json = require("rescript/lib/js/js_json.js");
|
|
6
|
+
var Js_array = require("rescript/lib/js/js_array.js");
|
|
6
7
|
var Belt_Array = require("rescript/lib/js/belt_Array.js");
|
|
7
8
|
var Belt_Result = require("rescript/lib/js/belt_Result.js");
|
|
8
9
|
|
|
@@ -58,7 +59,7 @@ function t1_decode(v) {
|
|
|
58
59
|
if (json_arr$1.length === 0) {
|
|
59
60
|
return Spice.error(undefined, "Expected variant, found empty array", v);
|
|
60
61
|
}
|
|
61
|
-
var tagged =
|
|
62
|
+
var tagged = Js_array.map(Js_json.classify, json_arr$1);
|
|
62
63
|
var match = Belt_Array.getExn(tagged, 0);
|
|
63
64
|
if (typeof match !== "number" && match.TAG === /* JSONString */0) {
|
|
64
65
|
switch (match._0) {
|
package/test/yarn.lock
CHANGED
|
@@ -3466,10 +3466,10 @@ require-main-filename@^2.0.0:
|
|
|
3466
3466
|
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
|
|
3467
3467
|
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
|
|
3468
3468
|
|
|
3469
|
-
rescript@^
|
|
3470
|
-
version "
|
|
3471
|
-
resolved "https://registry.yarnpkg.com/rescript/-/rescript-
|
|
3472
|
-
integrity sha512-
|
|
3469
|
+
rescript@^10.0.1:
|
|
3470
|
+
version "10.0.1"
|
|
3471
|
+
resolved "https://registry.yarnpkg.com/rescript/-/rescript-10.0.1.tgz#5b2da8a8bcfb994bed1eb24820bf10cfb9d8c440"
|
|
3472
|
+
integrity sha512-XwO1GPDtoEU4H03xQE5bp0/qtSVR6YLaJRPxWKrfFgKc+LI36ODOCie7o9UJfgzQdoMYkkZyiTGZ4N9OQEaiUw==
|
|
3473
3473
|
|
|
3474
3474
|
resolve-cwd@^3.0.0:
|
|
3475
3475
|
version "3.0.0"
|
package/src/ppx_spice.install
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
lib: [
|
|
2
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/META"
|
|
3
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/dune-package"
|
|
4
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/opam"
|
|
5
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/polyvariants.ml"
|
|
6
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice.a"
|
|
7
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice.cma"
|
|
8
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice.cmi"
|
|
9
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice.cmt"
|
|
10
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice.cmx"
|
|
11
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice.cmxa"
|
|
12
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice.ml"
|
|
13
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__.cmi"
|
|
14
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__.cmt"
|
|
15
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__.cmx"
|
|
16
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__.ml"
|
|
17
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__Polyvariants.cmi"
|
|
18
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__Polyvariants.cmt"
|
|
19
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__Polyvariants.cmx"
|
|
20
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__Signature.cmi"
|
|
21
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__Signature.cmt"
|
|
22
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__Signature.cmx"
|
|
23
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__Structure.cmi"
|
|
24
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__Structure.cmt"
|
|
25
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__Structure.cmx"
|
|
26
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__Utils.cmi"
|
|
27
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__Utils.cmt"
|
|
28
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__Utils.cmx"
|
|
29
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__Variants.cmi"
|
|
30
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__Variants.cmt"
|
|
31
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice__Variants.cmx"
|
|
32
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/signature.ml"
|
|
33
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/structure.ml"
|
|
34
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/utils.ml"
|
|
35
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/variants.ml"
|
|
36
|
-
]
|
|
37
|
-
libexec: [
|
|
38
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx.exe"
|
|
39
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/lib/ppx_spice/ppx_spice.cmxs"
|
|
40
|
-
]
|
|
41
|
-
bin: [
|
|
42
|
-
"/Users/woonki/Documents/projects/ppx_spice/src/_esy/default/store/b/ppx__spice-dc255e86/install/default/bin/ppx_spice"
|
|
43
|
-
]
|