@kaiko.io/rescript-deser 7.0.0 → 8.0.0-alpha.1
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/CHANGELOG.md +163 -0
- package/lib/bs/.compiler.log +2 -2
- package/lib/bs/compiler-info.json +1 -1
- package/lib/bs/src/Deser.ast +0 -0
- package/lib/bs/src/Deser.cmi +0 -0
- package/lib/bs/src/Deser.cmj +0 -0
- package/lib/bs/src/Deser.cmt +0 -0
- package/lib/bs/src/Deser.res +88 -3
- package/lib/bs/tests/index.ast +0 -0
- package/lib/bs/tests/index.cmi +0 -0
- package/lib/bs/tests/index.cmj +0 -0
- package/lib/bs/tests/index.cmt +0 -0
- package/lib/bs/tests/index.res +176 -31
- package/lib/es6/src/Deser.js +117 -3
- package/lib/es6/tests/index.js +221 -62
- package/lib/js/src/Deser.js +117 -3
- package/lib/js/tests/index.js +221 -62
- package/lib/ocaml/.compiler.log +2 -2
- package/lib/ocaml/Deser.ast +0 -0
- package/lib/ocaml/Deser.cmi +0 -0
- package/lib/ocaml/Deser.cmj +0 -0
- package/lib/ocaml/Deser.cmt +0 -0
- package/lib/ocaml/Deser.res +88 -3
- package/lib/ocaml/index.ast +0 -0
- package/lib/ocaml/index.cmi +0 -0
- package/lib/ocaml/index.cmj +0 -0
- package/lib/ocaml/index.cmt +0 -0
- package/lib/ocaml/index.res +176 -31
- package/lib/rescript.lock +1 -1
- package/package.json +1 -1
- package/src/Deser.res +88 -3
- package/tests/index.res +176 -31
package/lib/es6/src/Deser.js
CHANGED
|
@@ -429,6 +429,97 @@ function checkFieldsSanity(name, _fields, _optional) {
|
|
|
429
429
|
};
|
|
430
430
|
}
|
|
431
431
|
|
|
432
|
+
function isSafeCast(_field) {
|
|
433
|
+
while (true) {
|
|
434
|
+
let field = _field;
|
|
435
|
+
if (typeof field !== "object") {
|
|
436
|
+
switch (field) {
|
|
437
|
+
case "Date" :
|
|
438
|
+
case "Datetime" :
|
|
439
|
+
return false;
|
|
440
|
+
default:
|
|
441
|
+
return true;
|
|
442
|
+
}
|
|
443
|
+
} else {
|
|
444
|
+
switch (field.TAG) {
|
|
445
|
+
case "Tuple" :
|
|
446
|
+
return field._0.every(isSafeCast);
|
|
447
|
+
case "Object" :
|
|
448
|
+
return field._0.every(param => isSafeCast(param[1]));
|
|
449
|
+
case "Deserializer" :
|
|
450
|
+
case "Collection" :
|
|
451
|
+
return field._0.isSafeCast();
|
|
452
|
+
case "Array" :
|
|
453
|
+
case "Optional" :
|
|
454
|
+
case "OptionalWithDefault" :
|
|
455
|
+
case "Mapping" :
|
|
456
|
+
case "DefaultWhenInvalid" :
|
|
457
|
+
case "Morphism" :
|
|
458
|
+
_field = field._0;
|
|
459
|
+
continue;
|
|
460
|
+
default:
|
|
461
|
+
return true;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function serialize(_value, _shape, self) {
|
|
468
|
+
while (true) {
|
|
469
|
+
let shape = _shape;
|
|
470
|
+
let value = _value;
|
|
471
|
+
if (typeof shape !== "object") {
|
|
472
|
+
switch (shape) {
|
|
473
|
+
case "Date" :
|
|
474
|
+
case "Datetime" :
|
|
475
|
+
return value.toISOString();
|
|
476
|
+
case "Self" :
|
|
477
|
+
_shape = self;
|
|
478
|
+
continue;
|
|
479
|
+
default:
|
|
480
|
+
return value;
|
|
481
|
+
}
|
|
482
|
+
} else {
|
|
483
|
+
switch (shape.TAG) {
|
|
484
|
+
case "Literal" :
|
|
485
|
+
return shape._0;
|
|
486
|
+
case "Array" :
|
|
487
|
+
let inner = shape._0;
|
|
488
|
+
return value.map(v => serialize(v, inner, self));
|
|
489
|
+
case "Tuple" :
|
|
490
|
+
return Belt_Array.zipBy(value, shape._0, (v, f) => serialize(v, f, self));
|
|
491
|
+
case "Object" :
|
|
492
|
+
return Object.fromEntries(Stdlib_Array.filterMap(shape._0, param => {
|
|
493
|
+
let fieldType = param[1];
|
|
494
|
+
let key = param[0];
|
|
495
|
+
return Stdlib_Option.map(value[key], fieldValue => [
|
|
496
|
+
key,
|
|
497
|
+
serialize(fieldValue, fieldType, self)
|
|
498
|
+
]);
|
|
499
|
+
}));
|
|
500
|
+
case "Optional" :
|
|
501
|
+
if (value === undefined) {
|
|
502
|
+
return null;
|
|
503
|
+
}
|
|
504
|
+
_shape = shape._0;
|
|
505
|
+
_value = Primitive_option.valFromOption(value);
|
|
506
|
+
continue;
|
|
507
|
+
case "Mapping" :
|
|
508
|
+
let inner$1 = shape._0;
|
|
509
|
+
return Stdlib_Dict.mapValues(value, v => serialize(v, inner$1, self));
|
|
510
|
+
case "Deserializer" :
|
|
511
|
+
case "Collection" :
|
|
512
|
+
return shape._0.toJSON(value);
|
|
513
|
+
case "OptionalWithDefault" :
|
|
514
|
+
case "DefaultWhenInvalid" :
|
|
515
|
+
case "Morphism" :
|
|
516
|
+
_shape = shape._0;
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
|
|
432
523
|
let Field = {
|
|
433
524
|
usingString: usingString,
|
|
434
525
|
usingInt: usingInt,
|
|
@@ -442,12 +533,26 @@ let Field = {
|
|
|
442
533
|
_taggedToString: _taggedToString,
|
|
443
534
|
extractValue: extractValue,
|
|
444
535
|
fromUntagged: fromUntagged,
|
|
445
|
-
checkFieldsSanity: checkFieldsSanity
|
|
536
|
+
checkFieldsSanity: checkFieldsSanity,
|
|
537
|
+
isSafeCast: isSafeCast,
|
|
538
|
+
serialize: serialize
|
|
446
539
|
};
|
|
447
540
|
|
|
448
541
|
function MakeDeserializer(S) {
|
|
449
542
|
let fields = S.fields;
|
|
450
|
-
let name = `Deserializer ` + "Deser" + `, ` + "File \"Deser.res\", line
|
|
543
|
+
let name = `Deserializer ` + "Deser" + `, ` + "File \"Deser.res\", line 380, characters 29-37";
|
|
544
|
+
let safeCastCache = {
|
|
545
|
+
contents: undefined
|
|
546
|
+
};
|
|
547
|
+
let isSafeCast$1 = () => {
|
|
548
|
+
let cached = safeCastCache.contents;
|
|
549
|
+
if (cached !== undefined) {
|
|
550
|
+
return cached;
|
|
551
|
+
}
|
|
552
|
+
let result = isSafeCast(fields);
|
|
553
|
+
safeCastCache.contents = result;
|
|
554
|
+
return result;
|
|
555
|
+
};
|
|
451
556
|
let checkFieldsSanity$1 = () => checkFieldsSanity(name, fields, false);
|
|
452
557
|
let fromJSON = json => {
|
|
453
558
|
let res;
|
|
@@ -468,10 +573,19 @@ function MakeDeserializer(S) {
|
|
|
468
573
|
_0: res
|
|
469
574
|
};
|
|
470
575
|
};
|
|
576
|
+
let toJSON = value => {
|
|
577
|
+
if (isSafeCast$1()) {
|
|
578
|
+
return value;
|
|
579
|
+
} else {
|
|
580
|
+
return serialize(value, fields, fields);
|
|
581
|
+
}
|
|
582
|
+
};
|
|
471
583
|
return {
|
|
472
584
|
name: name,
|
|
473
585
|
fromJSON: fromJSON,
|
|
474
|
-
|
|
586
|
+
toJSON: toJSON,
|
|
587
|
+
checkFieldsSanity: checkFieldsSanity$1,
|
|
588
|
+
isSafeCast: isSafeCast$1
|
|
475
589
|
};
|
|
476
590
|
}
|
|
477
591
|
|
package/lib/es6/tests/index.js
CHANGED
|
@@ -34,6 +34,59 @@ let Appointment = {
|
|
|
34
34
|
Deserializer: Deserializer
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
+
let fields$1 = {
|
|
38
|
+
TAG: "Object",
|
|
39
|
+
_0: [
|
|
40
|
+
[
|
|
41
|
+
"head",
|
|
42
|
+
"String"
|
|
43
|
+
],
|
|
44
|
+
[
|
|
45
|
+
"tail",
|
|
46
|
+
{
|
|
47
|
+
TAG: "Optional",
|
|
48
|
+
_0: "Self"
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
]
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
let Deserializer$1 = Deser.MakeDeserializer({
|
|
55
|
+
fields: fields$1
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
let List = {
|
|
59
|
+
Deserializer: Deserializer$1
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
let fields$2 = {
|
|
63
|
+
TAG: "Object",
|
|
64
|
+
_0: [
|
|
65
|
+
[
|
|
66
|
+
"records",
|
|
67
|
+
{
|
|
68
|
+
TAG: "Deserializer",
|
|
69
|
+
_0: Deserializer$1
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
[
|
|
73
|
+
"next",
|
|
74
|
+
{
|
|
75
|
+
TAG: "Optional",
|
|
76
|
+
_0: "Self"
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
]
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
let Deserializer$2 = Deser.MakeDeserializer({
|
|
83
|
+
fields: fields$2
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
let Ledger = {
|
|
87
|
+
Deserializer: Deserializer$2
|
|
88
|
+
};
|
|
89
|
+
|
|
37
90
|
Qunit.module("Basic deserializer", param => {
|
|
38
91
|
let valid = [
|
|
39
92
|
[
|
|
@@ -164,27 +217,8 @@ Qunit.module("Recursive deserializer", param => {
|
|
|
164
217
|
qunit.deepEqual(Stdlib_Result.isError(InfiniteList.checkFieldsSanity()), true, "Ok");
|
|
165
218
|
});
|
|
166
219
|
Qunit.test("Finite list", qunit => {
|
|
167
|
-
let fields = {
|
|
168
|
-
TAG: "Object",
|
|
169
|
-
_0: [
|
|
170
|
-
[
|
|
171
|
-
"head",
|
|
172
|
-
"String"
|
|
173
|
-
],
|
|
174
|
-
[
|
|
175
|
-
"tail",
|
|
176
|
-
{
|
|
177
|
-
TAG: "Optional",
|
|
178
|
-
_0: "Self"
|
|
179
|
-
}
|
|
180
|
-
]
|
|
181
|
-
]
|
|
182
|
-
};
|
|
183
|
-
let List = Deser.MakeDeserializer({
|
|
184
|
-
fields: fields
|
|
185
|
-
});
|
|
186
220
|
qunit.expect(1);
|
|
187
|
-
qunit.deepEqual(
|
|
221
|
+
qunit.deepEqual(Deserializer$1.checkFieldsSanity(), {
|
|
188
222
|
TAG: "Ok",
|
|
189
223
|
_0: undefined
|
|
190
224
|
}, "Ok");
|
|
@@ -203,47 +237,6 @@ Qunit.module("Recursive deserializer", param => {
|
|
|
203
237
|
});
|
|
204
238
|
});
|
|
205
239
|
Qunit.test("Recursion in sub-deserializer", qunit => {
|
|
206
|
-
let fields = {
|
|
207
|
-
TAG: "Object",
|
|
208
|
-
_0: [
|
|
209
|
-
[
|
|
210
|
-
"head",
|
|
211
|
-
"String"
|
|
212
|
-
],
|
|
213
|
-
[
|
|
214
|
-
"tail",
|
|
215
|
-
{
|
|
216
|
-
TAG: "Optional",
|
|
217
|
-
_0: "Self"
|
|
218
|
-
}
|
|
219
|
-
]
|
|
220
|
-
]
|
|
221
|
-
};
|
|
222
|
-
let List = Deser.MakeDeserializer({
|
|
223
|
-
fields: fields
|
|
224
|
-
});
|
|
225
|
-
let fields$1 = {
|
|
226
|
-
TAG: "Object",
|
|
227
|
-
_0: [
|
|
228
|
-
[
|
|
229
|
-
"records",
|
|
230
|
-
{
|
|
231
|
-
TAG: "Deserializer",
|
|
232
|
-
_0: List
|
|
233
|
-
}
|
|
234
|
-
],
|
|
235
|
-
[
|
|
236
|
-
"next",
|
|
237
|
-
{
|
|
238
|
-
TAG: "Optional",
|
|
239
|
-
_0: "Self"
|
|
240
|
-
}
|
|
241
|
-
]
|
|
242
|
-
]
|
|
243
|
-
};
|
|
244
|
-
let Ledger = Deser.MakeDeserializer({
|
|
245
|
-
fields: fields$1
|
|
246
|
-
});
|
|
247
240
|
let data = {"records": {"head": "A", "tail": {"head": "B"}},
|
|
248
241
|
"next": {"records": {"head": "A", "tail": {"head": "B"}}}};
|
|
249
242
|
let expected = {
|
|
@@ -266,7 +259,7 @@ Qunit.module("Recursive deserializer", param => {
|
|
|
266
259
|
}
|
|
267
260
|
};
|
|
268
261
|
qunit.expect(1);
|
|
269
|
-
qunit.deepEqual(
|
|
262
|
+
qunit.deepEqual(Deserializer$2.fromJSON(data), {
|
|
270
263
|
TAG: "Ok",
|
|
271
264
|
_0: expected
|
|
272
265
|
}, "nice ledger");
|
|
@@ -296,7 +289,173 @@ Qunit.module("Type safety limits", param => {
|
|
|
296
289
|
});
|
|
297
290
|
});
|
|
298
291
|
|
|
292
|
+
Qunit.module("isSafeCast and toJSON", param => {
|
|
293
|
+
let fields = {
|
|
294
|
+
TAG: "Object",
|
|
295
|
+
_0: [
|
|
296
|
+
[
|
|
297
|
+
"name",
|
|
298
|
+
"String"
|
|
299
|
+
],
|
|
300
|
+
[
|
|
301
|
+
"count",
|
|
302
|
+
"Int"
|
|
303
|
+
],
|
|
304
|
+
[
|
|
305
|
+
"ratio",
|
|
306
|
+
"Float"
|
|
307
|
+
],
|
|
308
|
+
[
|
|
309
|
+
"active",
|
|
310
|
+
"Boolean"
|
|
311
|
+
]
|
|
312
|
+
]
|
|
313
|
+
};
|
|
314
|
+
let Deserializer$3 = Deser.MakeDeserializer({
|
|
315
|
+
fields: fields
|
|
316
|
+
});
|
|
317
|
+
let fields$1 = {
|
|
318
|
+
TAG: "Object",
|
|
319
|
+
_0: [
|
|
320
|
+
[
|
|
321
|
+
"items",
|
|
322
|
+
{
|
|
323
|
+
TAG: "Array",
|
|
324
|
+
_0: "String"
|
|
325
|
+
}
|
|
326
|
+
],
|
|
327
|
+
[
|
|
328
|
+
"tags",
|
|
329
|
+
{
|
|
330
|
+
TAG: "Mapping",
|
|
331
|
+
_0: "Int"
|
|
332
|
+
}
|
|
333
|
+
],
|
|
334
|
+
[
|
|
335
|
+
"label",
|
|
336
|
+
{
|
|
337
|
+
TAG: "Optional",
|
|
338
|
+
_0: "String"
|
|
339
|
+
}
|
|
340
|
+
]
|
|
341
|
+
]
|
|
342
|
+
};
|
|
343
|
+
let Deserializer$4 = Deser.MakeDeserializer({
|
|
344
|
+
fields: fields$1
|
|
345
|
+
});
|
|
346
|
+
let fields$2 = {
|
|
347
|
+
TAG: "Object",
|
|
348
|
+
_0: [
|
|
349
|
+
[
|
|
350
|
+
"name",
|
|
351
|
+
"String"
|
|
352
|
+
],
|
|
353
|
+
[
|
|
354
|
+
"created",
|
|
355
|
+
"Date"
|
|
356
|
+
]
|
|
357
|
+
]
|
|
358
|
+
};
|
|
359
|
+
let Deserializer$5 = Deser.MakeDeserializer({
|
|
360
|
+
fields: fields$2
|
|
361
|
+
});
|
|
362
|
+
let fields$3 = {
|
|
363
|
+
TAG: "Object",
|
|
364
|
+
_0: [[
|
|
365
|
+
"event",
|
|
366
|
+
{
|
|
367
|
+
TAG: "Deserializer",
|
|
368
|
+
_0: Deserializer$5
|
|
369
|
+
}
|
|
370
|
+
]]
|
|
371
|
+
};
|
|
372
|
+
let Deserializer$6 = Deser.MakeDeserializer({
|
|
373
|
+
fields: fields$3
|
|
374
|
+
});
|
|
375
|
+
Qunit.test("Safe types: primitives return true for isSafeCast", qunit => {
|
|
376
|
+
qunit.expect(1);
|
|
377
|
+
qunit.true(Deserializer$3.isSafeCast(), "primitives are safe");
|
|
378
|
+
});
|
|
379
|
+
Qunit.test("Safe types: nested arrays/mappings/optionals return true for isSafeCast", qunit => {
|
|
380
|
+
qunit.expect(1);
|
|
381
|
+
qunit.true(Deserializer$4.isSafeCast(), "nested safe types are safe");
|
|
382
|
+
});
|
|
383
|
+
Qunit.test("Unsafe types: Date returns false for isSafeCast", qunit => {
|
|
384
|
+
qunit.expect(1);
|
|
385
|
+
qunit.false(Deserializer$5.isSafeCast(), "Date is unsafe");
|
|
386
|
+
});
|
|
387
|
+
Qunit.test("Unsafe types: nested deserializer with Date returns false", qunit => {
|
|
388
|
+
qunit.expect(1);
|
|
389
|
+
qunit.false(Deserializer$6.isSafeCast(), "nested unsafe is unsafe");
|
|
390
|
+
});
|
|
391
|
+
Qunit.test("Round-trip for safe types", qunit => {
|
|
392
|
+
let json = {"name": "test", "count": 42, "ratio": 3.14, "active": true};
|
|
393
|
+
let value = Deserializer$3.fromJSON(json);
|
|
394
|
+
if (value.TAG === "Ok") {
|
|
395
|
+
let serialized = Deserializer$3.toJSON(value._0);
|
|
396
|
+
qunit.deepEqual(serialized, json, "round-trip preserves data");
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
qunit.false(true, value._0);
|
|
400
|
+
});
|
|
401
|
+
Qunit.test("Round-trip for unsafe types with Date", qunit => {
|
|
402
|
+
let json = {"name": "event", "created": "2024-01-15T10:30:00.000Z"};
|
|
403
|
+
let value = Deserializer$5.fromJSON(json);
|
|
404
|
+
if (value.TAG === "Ok") {
|
|
405
|
+
let serialized = Deserializer$5.toJSON(value._0);
|
|
406
|
+
qunit.deepEqual(serialized, json, "round-trip preserves data with Date");
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
qunit.false(true, value._0);
|
|
410
|
+
});
|
|
411
|
+
Qunit.test("Nested deserializer safety propagation", qunit => {
|
|
412
|
+
let json = {"event": {"name": "meeting", "created": "2024-06-01T09:00:00.000Z"}};
|
|
413
|
+
let value = Deserializer$6.fromJSON(json);
|
|
414
|
+
if (value.TAG === "Ok") {
|
|
415
|
+
let serialized = Deserializer$6.toJSON(value._0);
|
|
416
|
+
qunit.deepEqual(serialized, json, "nested unsafe round-trip works");
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
qunit.false(true, value._0);
|
|
420
|
+
});
|
|
421
|
+
Qunit.test("Morphism of safe type is safe", qunit => {
|
|
422
|
+
let fields_1 = v => v;
|
|
423
|
+
let fields = {
|
|
424
|
+
TAG: "Morphism",
|
|
425
|
+
_0: "Int",
|
|
426
|
+
_1: fields_1
|
|
427
|
+
};
|
|
428
|
+
let WithMorphism = Deser.MakeDeserializer({
|
|
429
|
+
fields: fields
|
|
430
|
+
});
|
|
431
|
+
qunit.expect(1);
|
|
432
|
+
qunit.true(WithMorphism.isSafeCast(), "morphism of Int is safe");
|
|
433
|
+
});
|
|
434
|
+
Qunit.test("List deserializer is safe (recursive with Self)", qunit => {
|
|
435
|
+
qunit.expect(1);
|
|
436
|
+
qunit.true(Deserializer$1.isSafeCast(), "recursive list with strings is safe");
|
|
437
|
+
});
|
|
438
|
+
Qunit.test("Appointment deserializer is unsafe (has Date)", qunit => {
|
|
439
|
+
qunit.expect(1);
|
|
440
|
+
qunit.false(Deserializer.isSafeCast(), "Appointment with Date is unsafe");
|
|
441
|
+
});
|
|
442
|
+
Qunit.test("toJSON serializes Date to ISO string", qunit => {
|
|
443
|
+
let appointment_date = new Date("2024-03-15T14:30:00.000Z");
|
|
444
|
+
let appointment_extra = "extra info";
|
|
445
|
+
let appointment = {
|
|
446
|
+
note: "Test",
|
|
447
|
+
date: appointment_date,
|
|
448
|
+
extra: appointment_extra
|
|
449
|
+
};
|
|
450
|
+
let json = Deserializer.toJSON(appointment);
|
|
451
|
+
let expected = {"note": "Test", "date": "2024-03-15T14:30:00.000Z", "extra": "extra info"};
|
|
452
|
+
qunit.deepEqual(json, expected, "Date serialized to ISO string");
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
|
|
299
456
|
export {
|
|
300
457
|
Appointment,
|
|
458
|
+
List,
|
|
459
|
+
Ledger,
|
|
301
460
|
}
|
|
302
461
|
/* Deserializer Not a pure module */
|
package/lib/js/src/Deser.js
CHANGED
|
@@ -430,6 +430,97 @@ function checkFieldsSanity(name, _fields, _optional) {
|
|
|
430
430
|
};
|
|
431
431
|
}
|
|
432
432
|
|
|
433
|
+
function isSafeCast(_field) {
|
|
434
|
+
while (true) {
|
|
435
|
+
let field = _field;
|
|
436
|
+
if (typeof field !== "object") {
|
|
437
|
+
switch (field) {
|
|
438
|
+
case "Date" :
|
|
439
|
+
case "Datetime" :
|
|
440
|
+
return false;
|
|
441
|
+
default:
|
|
442
|
+
return true;
|
|
443
|
+
}
|
|
444
|
+
} else {
|
|
445
|
+
switch (field.TAG) {
|
|
446
|
+
case "Tuple" :
|
|
447
|
+
return field._0.every(isSafeCast);
|
|
448
|
+
case "Object" :
|
|
449
|
+
return field._0.every(param => isSafeCast(param[1]));
|
|
450
|
+
case "Deserializer" :
|
|
451
|
+
case "Collection" :
|
|
452
|
+
return field._0.isSafeCast();
|
|
453
|
+
case "Array" :
|
|
454
|
+
case "Optional" :
|
|
455
|
+
case "OptionalWithDefault" :
|
|
456
|
+
case "Mapping" :
|
|
457
|
+
case "DefaultWhenInvalid" :
|
|
458
|
+
case "Morphism" :
|
|
459
|
+
_field = field._0;
|
|
460
|
+
continue;
|
|
461
|
+
default:
|
|
462
|
+
return true;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function serialize(_value, _shape, self) {
|
|
469
|
+
while (true) {
|
|
470
|
+
let shape = _shape;
|
|
471
|
+
let value = _value;
|
|
472
|
+
if (typeof shape !== "object") {
|
|
473
|
+
switch (shape) {
|
|
474
|
+
case "Date" :
|
|
475
|
+
case "Datetime" :
|
|
476
|
+
return value.toISOString();
|
|
477
|
+
case "Self" :
|
|
478
|
+
_shape = self;
|
|
479
|
+
continue;
|
|
480
|
+
default:
|
|
481
|
+
return value;
|
|
482
|
+
}
|
|
483
|
+
} else {
|
|
484
|
+
switch (shape.TAG) {
|
|
485
|
+
case "Literal" :
|
|
486
|
+
return shape._0;
|
|
487
|
+
case "Array" :
|
|
488
|
+
let inner = shape._0;
|
|
489
|
+
return value.map(v => serialize(v, inner, self));
|
|
490
|
+
case "Tuple" :
|
|
491
|
+
return Belt_Array.zipBy(value, shape._0, (v, f) => serialize(v, f, self));
|
|
492
|
+
case "Object" :
|
|
493
|
+
return Object.fromEntries(Stdlib_Array.filterMap(shape._0, param => {
|
|
494
|
+
let fieldType = param[1];
|
|
495
|
+
let key = param[0];
|
|
496
|
+
return Stdlib_Option.map(value[key], fieldValue => [
|
|
497
|
+
key,
|
|
498
|
+
serialize(fieldValue, fieldType, self)
|
|
499
|
+
]);
|
|
500
|
+
}));
|
|
501
|
+
case "Optional" :
|
|
502
|
+
if (value === undefined) {
|
|
503
|
+
return null;
|
|
504
|
+
}
|
|
505
|
+
_shape = shape._0;
|
|
506
|
+
_value = Primitive_option.valFromOption(value);
|
|
507
|
+
continue;
|
|
508
|
+
case "Mapping" :
|
|
509
|
+
let inner$1 = shape._0;
|
|
510
|
+
return Stdlib_Dict.mapValues(value, v => serialize(v, inner$1, self));
|
|
511
|
+
case "Deserializer" :
|
|
512
|
+
case "Collection" :
|
|
513
|
+
return shape._0.toJSON(value);
|
|
514
|
+
case "OptionalWithDefault" :
|
|
515
|
+
case "DefaultWhenInvalid" :
|
|
516
|
+
case "Morphism" :
|
|
517
|
+
_shape = shape._0;
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
433
524
|
let Field = {
|
|
434
525
|
usingString: usingString,
|
|
435
526
|
usingInt: usingInt,
|
|
@@ -443,12 +534,26 @@ let Field = {
|
|
|
443
534
|
_taggedToString: _taggedToString,
|
|
444
535
|
extractValue: extractValue,
|
|
445
536
|
fromUntagged: fromUntagged,
|
|
446
|
-
checkFieldsSanity: checkFieldsSanity
|
|
537
|
+
checkFieldsSanity: checkFieldsSanity,
|
|
538
|
+
isSafeCast: isSafeCast,
|
|
539
|
+
serialize: serialize
|
|
447
540
|
};
|
|
448
541
|
|
|
449
542
|
function MakeDeserializer(S) {
|
|
450
543
|
let fields = S.fields;
|
|
451
|
-
let name = `Deserializer ` + "Deser" + `, ` + "File \"Deser.res\", line
|
|
544
|
+
let name = `Deserializer ` + "Deser" + `, ` + "File \"Deser.res\", line 380, characters 29-37";
|
|
545
|
+
let safeCastCache = {
|
|
546
|
+
contents: undefined
|
|
547
|
+
};
|
|
548
|
+
let isSafeCast$1 = () => {
|
|
549
|
+
let cached = safeCastCache.contents;
|
|
550
|
+
if (cached !== undefined) {
|
|
551
|
+
return cached;
|
|
552
|
+
}
|
|
553
|
+
let result = isSafeCast(fields);
|
|
554
|
+
safeCastCache.contents = result;
|
|
555
|
+
return result;
|
|
556
|
+
};
|
|
452
557
|
let checkFieldsSanity$1 = () => checkFieldsSanity(name, fields, false);
|
|
453
558
|
let fromJSON = json => {
|
|
454
559
|
let res;
|
|
@@ -469,10 +574,19 @@ function MakeDeserializer(S) {
|
|
|
469
574
|
_0: res
|
|
470
575
|
};
|
|
471
576
|
};
|
|
577
|
+
let toJSON = value => {
|
|
578
|
+
if (isSafeCast$1()) {
|
|
579
|
+
return value;
|
|
580
|
+
} else {
|
|
581
|
+
return serialize(value, fields, fields);
|
|
582
|
+
}
|
|
583
|
+
};
|
|
472
584
|
return {
|
|
473
585
|
name: name,
|
|
474
586
|
fromJSON: fromJSON,
|
|
475
|
-
|
|
587
|
+
toJSON: toJSON,
|
|
588
|
+
checkFieldsSanity: checkFieldsSanity$1,
|
|
589
|
+
isSafeCast: isSafeCast$1
|
|
476
590
|
};
|
|
477
591
|
}
|
|
478
592
|
|