Skip to content

Commit 2f7cba0

Browse files
committed
Use optional args for JSON.stringify and JSON.parseExn
1 parent 6d2d3d8 commit 2f7cba0

File tree

7 files changed

+124
-25
lines changed

7 files changed

+124
-25
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Next version
44

5+
- Add optional arguments to `JSON.stringify` and `JSON.parseExn` and deprecate `JSON.stringifyWithIndent`, `JSON.stringifyWithReplacer`, `JSON.parseExnWithReviver` etc. https://github.com/rescript-association/rescript-core/pull/201
56
- BREAKING: Intl types: simplify bindings for constructors / functions with optional arguments. https://github.com/rescript-association/rescript-core/pull/198
67
- Fix: Expose Intl.Common. https://github.com/rescript-association/rescript-core/pull/197
78
- Add `Array.flatMapWithIndex` https://github.com/rescript-association/rescript-core/pull/199

scripts/DocTests.mjs

+3-3
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ function prepareCompiler() {
6565
stdio: "ignore",
6666
cwd: compilerDir
6767
});
68-
var dict = JSON.parse(Fs.readFileSync(Path.join(corePath, "package.json")));
68+
var dict = JSON.parse(Fs.readFileSync(Path.join(corePath, "package.json")), undefined);
6969
var currentCoreVersion;
7070
if (!Array.isArray(dict) && (dict === null || typeof dict !== "object") && typeof dict !== "number" && typeof dict !== "string" && typeof dict !== "boolean") {
7171
throw {
@@ -143,7 +143,7 @@ async function testCode(id, code) {
143143
"-I",
144144
rescriptCoreCompiled,
145145
"-w",
146-
"-109",
146+
"-3-109",
147147
"-uncurried",
148148
"-open",
149149
"RescriptCore"
@@ -179,7 +179,7 @@ function extractDocFromFile(file) {
179179
"doc",
180180
file
181181
]);
182-
return Tools_Docgen.decodeFromJson(JSON.parse(spawn.stdout.toString()));
182+
return Tools_Docgen.decodeFromJson(JSON.parse(spawn.stdout.toString(), undefined));
183183
}
184184

185185
function getExamples(param) {

scripts/DocTests.res

+1-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ let testCode = async (~id, ~code) => {
163163
"-I",
164164
rescriptCoreCompiled,
165165
"-w",
166-
"-109",
166+
"-3-109",
167167
"-uncurried",
168168
"-open",
169169
"RescriptCore",

src/Core__JSON.res

+26-13
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,38 @@ type rec t = Js.Json.t =
77
| Object(Core__Dict.t<t>)
88
| Array(array<t>)
99

10-
@raises @val external parseExn: string => t = "JSON.parse"
11-
@raises @val external parseExnWithReviver: (string, (string, t) => t) => t = "JSON.parse"
12-
@val external stringify: t => string = "JSON.stringify"
13-
@val external stringifyWithIndent: (t, @as(json`null`) _, int) => string = "JSON.stringify"
14-
@val external stringifyWithReplacer: (t, (string, t) => t) => string = "JSON.stringify"
15-
@val
10+
@unboxed
11+
type replacer = Keys(array<string>) | Replacer((string, t) => t)
12+
13+
@raises @val external parseExn: (string, ~reviver: (string, t) => t=?) => t = "JSON.parse"
14+
@deprecated("Use `parseExn` with optional parameter instead") @raises @val
15+
external parseExnWithReviver: (string, (string, t) => t) => t = "JSON.parse"
16+
17+
@val external stringify: (t, ~replacer: replacer=?, ~space: int=?) => string = "JSON.stringify"
18+
@deprecated("Use `stringify` with optional parameter instead") @val
19+
external stringifyWithIndent: (t, @as(json`null`) _, int) => string = "JSON.stringify"
20+
@deprecated("Use `stringify` with optional parameter instead") @val
21+
external stringifyWithReplacer: (t, (string, t) => t) => string = "JSON.stringify"
22+
@deprecated("Use `stringify` with optional parameters instead") @val
1623
external stringifyWithReplacerAndIndent: (t, (string, t) => t, int) => string = "JSON.stringify"
17-
@val external stringifyWithFilter: (t, array<string>) => string = "JSON.stringify"
18-
@val external stringifyWithFilterAndIndent: (t, array<string>, int) => string = "JSON.stringify"
19-
@raises @val external stringifyAny: 'a => option<string> = "JSON.stringify"
24+
@deprecated("Use `stringify` with optional parameter instead") @val
25+
external stringifyWithFilter: (t, array<string>) => string = "JSON.stringify"
26+
@deprecated("Use `stringify` with optional parameters instead") @val
27+
external stringifyWithFilterAndIndent: (t, array<string>, int) => string = "JSON.stringify"
28+
2029
@raises @val
30+
external stringifyAny: ('a, ~replacer: replacer=?, ~space: int=?) => option<string> =
31+
"JSON.stringify"
32+
@deprecated("Use `stringifyAny` with optional parameter instead") @raises @val
2133
external stringifyAnyWithIndent: ('a, @as(json`null`) _, int) => option<string> = "JSON.stringify"
22-
@raises @val
34+
@deprecated("Use `stringifyAny` with optional parameter instead") @raises @val
2335
external stringifyAnyWithReplacer: ('a, (string, t) => t) => option<string> = "JSON.stringify"
24-
@raises @val
36+
@deprecated("Use `stringifyAny` with optional parameters instead") @raises @val
2537
external stringifyAnyWithReplacerAndIndent: ('a, (string, t) => t, int) => option<string> =
2638
"JSON.stringify"
27-
@raises @val external stringifyAnyWithFilter: ('a, array<string>) => string = "JSON.stringify"
28-
@raises @val
39+
@deprecated("Use `stringifyAny` with optional parameter instead") @raises @val
40+
external stringifyAnyWithFilter: ('a, array<string>) => string = "JSON.stringify"
41+
@deprecated("Use `stringifyAny` with optional parameters instead") @raises @val
2942
external stringifyAnyWithFilterAndIndent: ('a, array<string>, int) => string = "JSON.stringify"
3043

3144
module Classify = {

src/Core__JSON.resi

+91-6
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ type rec t = Js.Json.t =
1414
| Object(Core__Dict.t<t>)
1515
| Array(array<t>)
1616

17+
@unboxed
18+
type replacer = Keys(array<string>) | Replacer((string, t) => t)
19+
1720
/**
18-
`parseExn(string)`
21+
`parseExn(string, ~reviver=?)`
1922

2023
Parses a JSON string or throws a JavaScript exception (SyntaxError), if the string isn't valid.
24+
The reviver describes how the value should be transformed. It is a function which receives a key and a value.
2125
It returns a JSON type.
2226

2327
## Examples
@@ -31,6 +35,28 @@ try {
3135
} catch {
3236
| Exn.Error(_) => Console.log("error")
3337
}
38+
39+
let reviver = (_, value) => {
40+
let valueType = JSON.Classify.classify(value)
41+
42+
switch valueType {
43+
| String(string) => string->String.toUpperCase->JSON.Encode.string
44+
| Number(number) => (number *. 2.0)->JSON.Encode.float
45+
| _ => value
46+
}
47+
}
48+
49+
let jsonString = `{"hello":"world","someNumber":21}`
50+
51+
try {
52+
JSON.parseExn(jsonString, ~reviver)->Console.log
53+
// { hello: 'WORLD', someNumber: 42 }
54+
55+
JSON.parseExn("", ~reviver)->Console.log
56+
// error
57+
} catch {
58+
| Exn.Error(_) => Console.log("error")
59+
}
3460
```
3561

3662
## Exceptions
@@ -39,7 +65,7 @@ try {
3965
*/
4066
@raises(Exn.t)
4167
@val
42-
external parseExn: string => t = "JSON.parse"
68+
external parseExn: (string, ~reviver: (string, t) => t=?) => t = "JSON.parse"
4369

4470
/**
4571
`parseExnWithReviver(string, reviver)`
@@ -77,14 +103,17 @@ try {
77103

78104
- Raises a SyntaxError if the string isn't valid JSON.
79105
*/
106+
@deprecated("Use `parseExn` with optional parameter instead")
80107
@raises(Exn.t)
81108
@val
82109
external parseExnWithReviver: (string, (string, t) => t) => t = "JSON.parse"
83110

84111
/**
85-
`stringify(json)`
112+
`stringify(json, ~replacer=?, ~space=?)`
86113

87114
Converts a JSON object to a JSON string.
115+
The replacer describes how the value should be transformed. It is a function which receives a key and a value,
116+
or an array of keys which should be included in the output.
88117
If you want to stringify any type, use `JSON.stringifyAny` instead.
89118

90119
## Examples
@@ -98,10 +127,32 @@ let json =
98127

99128
JSON.stringify(json)
100129
// {"foo":"bar","hello":"world","someNumber":42}
130+
131+
JSON.stringify(json, ~space=2)
132+
// {
133+
// "foo": "bar",
134+
// "hello": "world",
135+
// "someNumber": 42
136+
// }
137+
138+
JSON.stringify(json, ~replacer=Keys(["foo", "someNumber"]))
139+
// {"foo":"bar","someNumber":42}
140+
141+
let replacer = JSON.Replacer((_, value) => {
142+
let decodedValue = value->JSON.Decode.string
143+
144+
switch decodedValue {
145+
| Some(string) => string->String.toUpperCase->JSON.Encode.string
146+
| None => value
147+
}
148+
})
149+
150+
JSON.stringify(json, ~replacer)
151+
// {"foo":"BAR","hello":"WORLD","someNumber":42}
101152
```
102153
*/
103154
@val
104-
external stringify: t => string = "JSON.stringify"
155+
external stringify: (t, ~replacer: replacer=?, ~space: int=?) => string = "JSON.stringify"
105156

106157
/**
107158
`stringifyWithIndent(json, indentation)`
@@ -126,6 +177,7 @@ JSON.stringifyWithIndent(json, 2)
126177
// }
127178
```
128179
*/
180+
@deprecated("Use `stringify` with optional parameter instead")
129181
@val
130182
external stringifyWithIndent: (t, @as(json`null`) _, int) => string = "JSON.stringify"
131183

@@ -158,6 +210,7 @@ JSON.stringifyWithReplacer(json, replacer)
158210
// {"foo":"BAR","hello":"WORLD","someNumber":42}
159211
```
160212
*/
213+
@deprecated("Use `stringify` with optional parameter instead")
161214
@val
162215
external stringifyWithReplacer: (t, (string, t) => t) => string = "JSON.stringify"
163216

@@ -194,6 +247,7 @@ JSON.stringifyWithReplacerAndIndent(json, replacer, 2)
194247
// }
195248
```
196249
*/
250+
@deprecated("Use `stringify` with optional parameters instead")
197251
@val
198252
external stringifyWithReplacerAndIndent: (t, (string, t) => t, int) => string = "JSON.stringify"
199253

@@ -217,6 +271,7 @@ JSON.stringifyWithFilter(json, ["foo", "someNumber"])
217271
// {"foo":"bar","someNumber":42}
218272
```
219273
*/
274+
@deprecated("Use `stringify` with optional parameter instead")
220275
@val
221276
external stringifyWithFilter: (t, array<string>) => string = "JSON.stringify"
222277

@@ -243,13 +298,15 @@ JSON.stringifyWithFilterAndIndent(json, ["foo", "someNumber"], 2)
243298
// }
244299
```
245300
*/
301+
@deprecated("Use `stringify` with optional parameters instead")
246302
@val
247303
external stringifyWithFilterAndIndent: (t, array<string>, int) => string = "JSON.stringify"
248304

249305
/**
250-
`stringifyAny(any)`
306+
`stringifyAny(any, ~replacer=?, ~space=?)`
251307

252308
Converts any type to a JSON string.
309+
The replacer describes how the value should be transformed. It is a function which receives a key and a value.
253310
Stringifying a function or `undefined` will return `None`.
254311
If the value contains circular references or `BigInt`s, the function will throw a JavaScript exception (TypeError).
255312
If you want to stringify a JSON object, use `JSON.stringify` instead.
@@ -265,6 +322,28 @@ let dict = Dict.fromArray([
265322
JSON.stringifyAny(dict)
266323
// {"foo":"bar","hello":"world","someNumber":42}
267324

325+
JSON.stringifyAny(dict, ~space=2)
326+
// {
327+
// "foo": "bar",
328+
// "hello": "world",
329+
// "someNumber": 42
330+
// }
331+
332+
JSON.stringifyAny(dict, ~replacer=Keys(["foo", "someNumber"]))
333+
// {"foo":"bar","someNumber":42}
334+
335+
let replacer = JSON.Replacer((_, value) => {
336+
let decodedValue = value->JSON.Decode.string
337+
338+
switch decodedValue {
339+
| Some(string) => string->String.toUpperCase->JSON.Encode.string
340+
| None => value
341+
}
342+
})
343+
344+
JSON.stringifyAny(dict, ~replacer)
345+
// {"foo":"BAR","hello":"WORLD","someNumber":42}
346+
268347
JSON.stringifyAny(() => "hello world")
269348
// None
270349

@@ -279,7 +358,8 @@ BigInt.fromInt(0)->JSON.stringifyAny
279358
*/
280359
@raises(Exn.t)
281360
@val
282-
external stringifyAny: 'a => option<string> = "JSON.stringify"
361+
external stringifyAny: ('a, ~replacer: replacer=?, ~space: int=?) => option<string> =
362+
"JSON.stringify"
283363

284364
/**
285365
`stringifyAnyWithIndent(any, indentation)`
@@ -316,6 +396,7 @@ BigInt.fromInt(0)->JSON.stringifyAny
316396
- Raises a TypeError if the value contains circular references.
317397
- Raises a TypeError if the value contains `BigInt`s.
318398
*/
399+
@deprecated("Use `stringifyAny` with optional parameter instead")
319400
@raises(Exn.t)
320401
@val
321402
external stringifyAnyWithIndent: ('a, @as(json`null`) _, int) => option<string> = "JSON.stringify"
@@ -361,6 +442,7 @@ BigInt.fromInt(0)->JSON.stringifyAny
361442
- Raises a TypeError if the value contains circular references.
362443
- Raises a TypeError if the value contains `BigInt`s.
363444
*/
445+
@deprecated("Use `stringifyAny` with optional parameter instead")
364446
@raises
365447
@val
366448
external stringifyAnyWithReplacer: ('a, (string, t) => t) => option<string> = "JSON.stringify"
@@ -410,6 +492,7 @@ BigInt.fromInt(0)->JSON.stringifyAny
410492
- Raises a TypeError if the value contains circular references.
411493
- Raises a TypeError if the value contains `BigInt`s.
412494
*/
495+
@deprecated("Use `stringifyAny` with optional parameters instead")
413496
@raises
414497
@val
415498
external stringifyAnyWithReplacerAndIndent: ('a, (string, t) => t, int) => option<string> =
@@ -447,6 +530,7 @@ BigInt.fromInt(0)->JSON.stringifyAny
447530
- Raises a TypeError if the value contains circular references.
448531
- Raises a TypeError if the value contains `BigInt`s.
449532
*/
533+
@deprecated("Use `stringifyAny` with optional parameter instead")
450534
@raises
451535
@val
452536
external stringifyAnyWithFilter: ('a, array<string>) => string = "JSON.stringify"
@@ -486,6 +570,7 @@ BigInt.fromInt(0)->JSON.stringifyAny
486570
- Raises a TypeError if the value contains circular references.
487571
- Raises a TypeError if the value contains `BigInt`s.
488572
*/
573+
@deprecated("Use `stringifyAny` with optional parameters instead")
489574
@raises
490575
@val
491576
external stringifyAnyWithFilterAndIndent: ('a, array<string>, int) => string = "JSON.stringify"

test/TempTests.mjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ console.info("JSON");
9898

9999
console.info("---");
100100

101-
var json = JSON.parse("{\"foo\": \"bar\"}");
101+
var json = JSON.parse("{\"foo\": \"bar\"}", undefined);
102102

103103
var json$1 = Core__JSON.Classify.classify(json);
104104

test/Test.mjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ function print(value) {
1313
if (match === "object" || match === "bigint") {
1414
return Util.inspect(value);
1515
} else if (match === "string") {
16-
return Core__Option.getExn(JSON.stringify(value));
16+
return Core__Option.getExn(JSON.stringify(value, undefined, undefined));
1717
} else {
1818
return String(value);
1919
}

0 commit comments

Comments
 (0)