@kaiko.io/rescript-deser 7.0.0-alpha.1 → 7.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.
Files changed (61) hide show
  1. package/README.md +13 -2
  2. package/lib/bs/.compiler.log +2 -2
  3. package/lib/bs/build.ninja +0 -27
  4. package/lib/bs/compiler-info.json +8 -0
  5. package/lib/bs/src/Deser.ast +0 -0
  6. package/lib/bs/src/Deser.cmi +0 -0
  7. package/lib/bs/src/Deser.cmj +0 -0
  8. package/lib/bs/src/Deser.cmt +0 -0
  9. package/lib/bs/{___incremental → src}/Deser.res +19 -29
  10. package/lib/bs/tests/QUnit.ast +0 -0
  11. package/lib/bs/tests/QUnit.cmi +0 -0
  12. package/lib/bs/tests/QUnit.cmj +0 -0
  13. package/lib/bs/tests/QUnit.cmt +0 -0
  14. package/lib/bs/tests/QUnit.res +72 -0
  15. package/lib/bs/tests/index.ast +0 -0
  16. package/lib/bs/tests/index.cmi +0 -0
  17. package/lib/bs/tests/index.cmj +0 -0
  18. package/lib/bs/tests/index.cmt +0 -0
  19. package/lib/bs/{___incremental → tests}/index.res +24 -1
  20. package/lib/es6/src/Deser.js +297 -365
  21. package/lib/es6/tests/index.js +260 -241
  22. package/lib/js/src/Deser.js +293 -361
  23. package/lib/js/tests/index.js +261 -242
  24. package/lib/ocaml/.compiler.log +2 -0
  25. package/lib/ocaml/Deser.ast +0 -0
  26. package/lib/ocaml/Deser.cmi +0 -0
  27. package/lib/ocaml/Deser.cmj +0 -0
  28. package/lib/ocaml/Deser.cmt +0 -0
  29. package/lib/ocaml/Deser.res +341 -0
  30. package/lib/ocaml/QUnit.ast +0 -0
  31. package/lib/ocaml/QUnit.cmi +0 -0
  32. package/lib/ocaml/QUnit.cmj +0 -0
  33. package/lib/ocaml/QUnit.cmt +0 -0
  34. package/lib/ocaml/QUnit.res +72 -0
  35. package/lib/ocaml/index.ast +0 -0
  36. package/lib/ocaml/index.cmi +0 -0
  37. package/lib/ocaml/index.cmj +0 -0
  38. package/lib/ocaml/index.cmt +0 -0
  39. package/lib/ocaml/index.res +212 -0
  40. package/lib/rescript.lock +1 -0
  41. package/package.json +4 -6
  42. package/rescript.json +4 -6
  43. package/src/Deser.res +19 -29
  44. package/tests/QUnit.res +4 -4
  45. package/tests/index.res +24 -1
  46. package/yarn.lock +683 -0
  47. package/lib/bs/.bsbuild +0 -0
  48. package/lib/bs/.bsdeps +0 -9
  49. package/lib/bs/.ninja_log +0 -57
  50. package/lib/bs/.project-files-cache +0 -0
  51. package/lib/bs/.sourcedirs.json +0 -1
  52. package/lib/bs/___incremental/Deser.cmi +0 -0
  53. package/lib/bs/___incremental/Deser.cmj +0 -0
  54. package/lib/bs/___incremental/Deser.cmt +0 -0
  55. package/lib/bs/___incremental/index.cmi +0 -0
  56. package/lib/bs/___incremental/index.cmj +0 -0
  57. package/lib/bs/___incremental/index.cmt +0 -0
  58. package/lib/bs/install.ninja +0 -10
  59. package/lib/bs/src/Deser.d +0 -0
  60. package/lib/bs/tests/QUnit.d +0 -0
  61. package/lib/bs/tests/index.d +0 -1
package/rescript.json CHANGED
@@ -10,16 +10,14 @@
10
10
  "type": "dev"
11
11
  }
12
12
  ],
13
- "bs-dependencies": [
14
- "@rescript/core"
15
- ],
16
- "uncurried": true,
17
13
  "package-specs": [
18
14
  {
19
- "module": "esmodule"
15
+ "module": "esmodule",
16
+ "in-source": false
20
17
  },
21
18
  {
22
- "module": "commonjs"
19
+ "module": "commonjs",
20
+ "in-source": false
23
21
  }
24
22
  ],
25
23
  "warnings": {
package/src/Deser.res CHANGED
@@ -1,5 +1,3 @@
1
- open RescriptCore
2
-
3
1
  module FieldValue = {
4
2
  type t
5
3
  external string: string => t = "%identity"
@@ -7,8 +5,8 @@ module FieldValue = {
7
5
  external float: float => t = "%identity"
8
6
  external boolean: bool => t = "%identity"
9
7
  external array: array<t> => t = "%identity"
10
- external object: Dict.t<t> => t = "%identity"
11
- external mapping: Dict.t<t> => t = "%identity"
8
+ external object: dict<t> => t = "%identity"
9
+ external mapping: dict<t> => t = "%identity"
12
10
  external any: 'a => t = "%identity"
13
11
  @val external null: t = "undefined"
14
12
 
@@ -46,7 +44,6 @@ module Field = {
46
44
  // We also allow floats and then use Date.fromTime
47
45
  | Date
48
46
  | Datetime // alias of Date
49
-
50
47
  | Tuple(array<t>)
51
48
  | Object(array<(string, t)>)
52
49
  | Optional(t)
@@ -55,21 +52,17 @@ module Field = {
55
52
  // difference with Object, is that you don't know the names of the
56
53
  // expected entries.
57
54
  | Mapping(t)
58
-
59
55
  | Deserializer(module(Deserializer))
60
-
61
56
  // A specialized Array of deserialized items that ignores unparsable
62
57
  // items and returns the valid collection. This saves the user from
63
58
  // writing 'Array(DefaultWhenInvalid(Optional(Deserializer(module(M)))))'
64
59
  // and then post-process the list of items with 'Array.keepSome'
65
60
  | Collection(module(Deserializer))
66
61
  | DefaultWhenInvalid(t, FieldValue.t)
67
-
68
62
  // FIXME: this is used to add additional restrictions like variadictInt or
69
63
  // variadicString; but I find it too type-unsafe. I might consider having
70
64
  // a Constraints for this in the future.
71
65
  | Morphism(t, FieldValue.t => FieldValue.t)
72
-
73
66
  | Self
74
67
 
75
68
  let usingString = (f: string => 'a) => value => value->FieldValue.asString->f->FieldValue.any
@@ -85,7 +78,7 @@ module Field = {
85
78
  switch i->fromJs {
86
79
  | Some(internalValue) => internalValue
87
80
  | None =>
88
- raise(TypeError(`This Int(${i->Int.toString}) not a valid value here. Hint: ${hint}`))
81
+ throw(TypeError(`This Int(${i->Int.toString}) not a valid value here. Hint: ${hint}`))
89
82
  }
90
83
  }),
91
84
  )
@@ -94,7 +87,7 @@ module Field = {
94
87
  usingString(i => {
95
88
  switch i->fromJs {
96
89
  | Some(internalValue) => internalValue
97
- | None => raise(TypeError(`This String("${i}") not a valid value here. Hint: ${hint}`))
90
+ | None => throw(TypeError(`This String("${i}") not a valid value here. Hint: ${hint}`))
98
91
  }
99
92
  }),
100
93
  )
@@ -147,12 +140,7 @@ module Field = {
147
140
  }
148
141
  }
149
142
 
150
- let rec extractValue = (
151
- values: Dict.t<JSON.t>,
152
- field: string,
153
- shape: t,
154
- self: t,
155
- ): FieldValue.t => {
143
+ let rec extractValue = (values: dict<JSON.t>, field: string, shape: t, self: t): FieldValue.t => {
156
144
  switch values->Dict.get(field) {
157
145
  | Some(value) => value->fromUntagged(shape, self)
158
146
  | None =>
@@ -160,7 +148,7 @@ module Field = {
160
148
  | DefaultWhenInvalid(_, _) => JSON.Null->fromUntagged(shape, self)
161
149
  | Optional(_) => JSON.Null->fromUntagged(shape, self)
162
150
  | OptionalWithDefault(_, default) => default
163
- | _ => raise(TypeError(`Missing non-optional field '${field}'`))
151
+ | _ => throw(TypeError(`Missing non-optional field '${field}'`))
164
152
  }
165
153
  }
166
154
  }
@@ -170,7 +158,7 @@ module Field = {
170
158
 
171
159
  | (Literal(expected), String(text)) if text == expected => FieldValue.string(text)
172
160
  | (Literal(expected), String(text)) =>
173
- raise(TypeError(`Expecting literal ${expected}, got ${text}`))
161
+ throw(TypeError(`Expecting literal ${expected}, got ${text}`))
174
162
 
175
163
  | (String, String(text)) => FieldValue.string(text)
176
164
 
@@ -187,7 +175,7 @@ module Field = {
187
175
  let values = Belt.Array.zipBy(items, bases, (i, b) => fromUntagged(i, b, self))
188
176
  values->FieldValue.array
189
177
  } else {
190
- raise(
178
+ throw(
191
179
  TypeError(`Expecting ${lenbases->Int.toString} items, got ${lenitems->Int.toString}`),
192
180
  )
193
181
  }
@@ -196,14 +184,14 @@ module Field = {
196
184
  | (Datetime | Date, String(s)) =>
197
185
  let r = Date.fromString(s)
198
186
  if r->Date.getDate->Int.toFloat->Float.isNaN {
199
- raise(TypeError(`Invalid date ${s}`))
187
+ throw(TypeError(`Invalid date ${s}`))
200
188
  }
201
189
  r->FieldValue.any
202
190
 
203
191
  | (Datetime | Date, Number(f)) =>
204
192
  let r = Date.fromTime(f)
205
193
  if r->Date.getDate->Int.toFloat->Float.isNaN {
206
- raise(TypeError(`Invalid date ${f->Float.toString}`))
194
+ throw(TypeError(`Invalid date ${f->Float.toString}`))
207
195
  }
208
196
  r->FieldValue.any
209
197
 
@@ -218,7 +206,7 @@ module Field = {
218
206
  ->Array.map(((field, shape)) => {
219
207
  let value = switch extractValue(values, field, shape, self) {
220
208
  | value => value
221
- | exception TypeError(msg) => raise(TypeError(`Field "${field}": ${msg}`))
209
+ | exception TypeError(msg) => throw(TypeError(`Field "${field}": ${msg}`))
222
210
  }
223
211
  (field, value)
224
212
  })
@@ -251,7 +239,7 @@ module Field = {
251
239
  module M = unpack(m: Deserializer)
252
240
  switch untagged->M.fromJSON {
253
241
  | Ok(res) => res->FieldValue.any
254
- | Error(msg) => raise(TypeError(msg))
242
+ | Error(msg) => throw(TypeError(msg))
255
243
  }
256
244
  }
257
245
 
@@ -265,7 +253,7 @@ module Field = {
265
253
  }
266
254
  | (Self, _) => untagged->fromUntagged(self, self)
267
255
  | (expected, actual) =>
268
- raise(TypeError(`Expected ${expected->toString}, but got ${actual->_taggedToString} instead`))
256
+ throw(TypeError(`Expected ${expected->toString}, but got ${actual->_taggedToString} instead`))
269
257
  }
270
258
  }
271
259
 
@@ -295,8 +283,9 @@ module Field = {
295
283
 
296
284
  | (Object(fields), optional) =>
297
285
  fields
298
- ->Array.map(((fieldName, field)) => () =>
299
- checkFieldsSanity(`${name}::${fieldName}`, field, optional))
286
+ ->Array.map(((fieldName, field)) =>
287
+ () => checkFieldsSanity(`${name}::${fieldName}`, field, optional)
288
+ )
300
289
  ->Array.reduce(Ok([]), (res, nextitem) =>
301
290
  res->Result.flatMap(arr => nextitem()->Result.map(i => arr->Array.concat([i])))
302
291
  )
@@ -308,8 +297,9 @@ module Field = {
308
297
 
309
298
  | (Tuple(fields), optional) =>
310
299
  fields
311
- ->Array.mapWithIndex((field, index) => () =>
312
- checkFieldsSanity(`${name}[${index->Int.toString}]`, field, optional))
300
+ ->Array.mapWithIndex((field, index) =>
301
+ () => checkFieldsSanity(`${name}[${index->Int.toString}]`, field, optional)
302
+ )
313
303
  ->Array.reduce(Ok([]), (res, nextitem) =>
314
304
  res->Result.flatMap(arr => nextitem()->Result.map(i => arr->Array.concat([i])))
315
305
  )
package/tests/QUnit.res CHANGED
@@ -48,12 +48,12 @@ type done = unit => unit
48
48
 
49
49
  @send external async: assertion => done = "async"
50
50
  @send external asyncMany: (assertion, int) => done = "async"
51
- @send external rejects: (assertion, Js.Promise.t<'a>, message) => unit = "rejects"
52
- @send external rejectsM: (assertion, Js.Promise.t<'a>, message) => unit = "rejects"
51
+ @send external rejects: (assertion, promise<'a>, message) => unit = "rejects"
52
+ @send external rejectsM: (assertion, promise<'a>, message) => unit = "rejects"
53
53
  @send
54
- external rejectMatches: (assertion, Js.Promise.t<'a>, matcher<'a>, message) => unit = "rejects"
54
+ external rejectMatches: (assertion, promise<'a>, matcher<'a>, message) => unit = "rejects"
55
55
  @send
56
- external rejectMatchesM: (assertion, Js.Promise.t<'a>, matcher<'a>, message) => unit = "rejects"
56
+ external rejectMatchesM: (assertion, promise<'a>, matcher<'a>, message) => unit = "rejects"
57
57
  @send external timeout: (assertion, int) => unit = "timeout"
58
58
 
59
59
  // Exceptions
package/tests/index.res CHANGED
@@ -1,5 +1,4 @@
1
1
  open QUnit
2
- open RescriptCore
3
2
 
4
3
  module Appointment = {
5
4
  type t = {
@@ -187,3 +186,27 @@ module_("Recursive deserializer", _ => {
187
186
  qunit->deepEqual(data->Ledger.fromJSON->Obj.magic, Ok(expected), "nice ledger")
188
187
  })
189
188
  })
189
+
190
+ module_("Type safety limits", _ => {
191
+ test("ill-defined deserializer can cheat the type system", qunit => {
192
+ module X = Deser.MakeDeserializer({
193
+ type t = string
194
+ let fields = Deser.Field.Array(Int)
195
+ })
196
+
197
+ let data = %raw("[1]")
198
+ qunit->throws(
199
+ _ => {
200
+ let illString = data->X.fromJSON->Result.getOr("")
201
+ try {
202
+ Console.info3(__MODULE__, "This will fail with a type error", illString->String.charAt(0))
203
+ } catch {
204
+ | e =>
205
+ Console.error(e)
206
+ throw(e)
207
+ }
208
+ },
209
+ "Expected: TypeError: illString.charAt is not a function",
210
+ )
211
+ })
212
+ })