Skip to content

Commit 6725ea4

Browse files
authored
Use optional args for JSON.stringify and JSON.parseExn (#201)
1 parent dedd5f6 commit 6725ea4

File tree

6 files changed

+121
-28
lines changed

6 files changed

+121
-28
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
- Add `Array.join` and deprecate `Array.joinWith`. https://github.com/rescript-association/rescript-core/pull/205
67
- BREAKING: Intl types: simplify bindings for constructors / functions with optional arguments. https://github.com/rescript-association/rescript-core/pull/198
78
- Fix: Expose Intl.Common. https://github.com/rescript-association/rescript-core/pull/197

scripts/DocTests.mjs

+2-2
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 {
@@ -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) {

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

+90-11
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,25 @@ try {
3135
} catch {
3236
| Exn.Error(_) => Console.log("error")
3337
}
38+
39+
let reviver = (_, value: JSON.t) =>
40+
switch value {
41+
| String(string) => string->String.toUpperCase->JSON.Encode.string
42+
| Number(number) => (number *. 2.0)->JSON.Encode.float
43+
| _ => value
44+
}
45+
46+
let jsonString = `{"hello":"world","someNumber":21}`
47+
48+
try {
49+
JSON.parseExn(jsonString, ~reviver)->Console.log
50+
// { hello: 'WORLD', someNumber: 42 }
51+
52+
JSON.parseExn("", ~reviver)->Console.log
53+
// error
54+
} catch {
55+
| Exn.Error(_) => Console.log("error")
56+
}
3457
```
3558

3659
## Exceptions
@@ -39,7 +62,7 @@ try {
3962
*/
4063
@raises(Exn.t)
4164
@val
42-
external parseExn: string => t = "JSON.parse"
65+
external parseExn: (string, ~reviver: (string, t) => t=?) => t = "JSON.parse"
4366

4467
/**
4568
`parseExnWithReviver(string, reviver)`
@@ -50,15 +73,12 @@ It returns a JSON type.
5073

5174
## Examples
5275
```rescript
53-
let reviver = (_, value) => {
54-
let valueType = JSON.Classify.classify(value)
55-
56-
switch valueType {
76+
let reviver = (_, value: JSON.t) =>
77+
switch value {
5778
| String(string) => string->String.toUpperCase->JSON.Encode.string
5879
| Number(number) => (number *. 2.0)->JSON.Encode.float
5980
| _ => value
6081
}
61-
}
6282

6383
let jsonString = `{"hello":"world","someNumber":21}`
6484

@@ -77,14 +97,17 @@ try {
7797

7898
- Raises a SyntaxError if the string isn't valid JSON.
7999
*/
100+
@deprecated("Use `parseExn` with optional parameter instead")
80101
@raises(Exn.t)
81102
@val
82103
external parseExnWithReviver: (string, (string, t) => t) => t = "JSON.parse"
83104

84105
/**
85-
`stringify(json)`
106+
`stringify(json, ~replacer=?, ~space=?)`
86107

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

90113
## Examples
@@ -98,10 +121,32 @@ let json =
98121

99122
JSON.stringify(json)
100123
// {"foo":"bar","hello":"world","someNumber":42}
124+
125+
JSON.stringify(json, ~space=2)
126+
// {
127+
// "foo": "bar",
128+
// "hello": "world",
129+
// "someNumber": 42
130+
// }
131+
132+
JSON.stringify(json, ~replacer=Keys(["foo", "someNumber"]))
133+
// {"foo":"bar","someNumber":42}
134+
135+
let replacer = JSON.Replacer((_, value) => {
136+
let decodedValue = value->JSON.Decode.string
137+
138+
switch decodedValue {
139+
| Some(string) => string->String.toUpperCase->JSON.Encode.string
140+
| None => value
141+
}
142+
})
143+
144+
JSON.stringify(json, ~replacer)
145+
// {"foo":"BAR","hello":"WORLD","someNumber":42}
101146
```
102147
*/
103148
@val
104-
external stringify: t => string = "JSON.stringify"
149+
external stringify: (t, ~replacer: replacer=?, ~space: int=?) => string = "JSON.stringify"
105150

106151
/**
107152
`stringifyWithIndent(json, indentation)`
@@ -126,6 +171,7 @@ JSON.stringifyWithIndent(json, 2)
126171
// }
127172
```
128173
*/
174+
@deprecated("Use `stringify` with optional parameter instead")
129175
@val
130176
external stringifyWithIndent: (t, @as(json`null`) _, int) => string = "JSON.stringify"
131177

@@ -158,6 +204,7 @@ JSON.stringifyWithReplacer(json, replacer)
158204
// {"foo":"BAR","hello":"WORLD","someNumber":42}
159205
```
160206
*/
207+
@deprecated("Use `stringify` with optional parameter instead")
161208
@val
162209
external stringifyWithReplacer: (t, (string, t) => t) => string = "JSON.stringify"
163210

@@ -194,6 +241,7 @@ JSON.stringifyWithReplacerAndIndent(json, replacer, 2)
194241
// }
195242
```
196243
*/
244+
@deprecated("Use `stringify` with optional parameters instead")
197245
@val
198246
external stringifyWithReplacerAndIndent: (t, (string, t) => t, int) => string = "JSON.stringify"
199247

@@ -217,6 +265,7 @@ JSON.stringifyWithFilter(json, ["foo", "someNumber"])
217265
// {"foo":"bar","someNumber":42}
218266
```
219267
*/
268+
@deprecated("Use `stringify` with optional parameter instead")
220269
@val
221270
external stringifyWithFilter: (t, array<string>) => string = "JSON.stringify"
222271

@@ -243,13 +292,15 @@ JSON.stringifyWithFilterAndIndent(json, ["foo", "someNumber"], 2)
243292
// }
244293
```
245294
*/
295+
@deprecated("Use `stringify` with optional parameters instead")
246296
@val
247297
external stringifyWithFilterAndIndent: (t, array<string>, int) => string = "JSON.stringify"
248298

249299
/**
250-
`stringifyAny(any)`
300+
`stringifyAny(any, ~replacer=?, ~space=?)`
251301

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

319+
JSON.stringifyAny(dict, ~space=2)
320+
// {
321+
// "foo": "bar",
322+
// "hello": "world",
323+
// "someNumber": 42
324+
// }
325+
326+
JSON.stringifyAny(dict, ~replacer=Keys(["foo", "someNumber"]))
327+
// {"foo":"bar","someNumber":42}
328+
329+
let replacer = JSON.Replacer((_, value) => {
330+
let decodedValue = value->JSON.Decode.string
331+
332+
switch decodedValue {
333+
| Some(string) => string->String.toUpperCase->JSON.Encode.string
334+
| None => value
335+
}
336+
})
337+
338+
JSON.stringifyAny(dict, ~replacer)
339+
// {"foo":"BAR","hello":"WORLD","someNumber":42}
340+
268341
JSON.stringifyAny(() => "hello world")
269342
// None
270343

@@ -279,7 +352,8 @@ BigInt.fromInt(0)->JSON.stringifyAny
279352
*/
280353
@raises(Exn.t)
281354
@val
282-
external stringifyAny: 'a => option<string> = "JSON.stringify"
355+
external stringifyAny: ('a, ~replacer: replacer=?, ~space: int=?) => option<string> =
356+
"JSON.stringify"
283357

284358
/**
285359
`stringifyAnyWithIndent(any, indentation)`
@@ -316,6 +390,7 @@ BigInt.fromInt(0)->JSON.stringifyAny
316390
- Raises a TypeError if the value contains circular references.
317391
- Raises a TypeError if the value contains `BigInt`s.
318392
*/
393+
@deprecated("Use `stringifyAny` with optional parameter instead")
319394
@raises(Exn.t)
320395
@val
321396
external stringifyAnyWithIndent: ('a, @as(json`null`) _, int) => option<string> = "JSON.stringify"
@@ -361,6 +436,7 @@ BigInt.fromInt(0)->JSON.stringifyAny
361436
- Raises a TypeError if the value contains circular references.
362437
- Raises a TypeError if the value contains `BigInt`s.
363438
*/
439+
@deprecated("Use `stringifyAny` with optional parameter instead")
364440
@raises
365441
@val
366442
external stringifyAnyWithReplacer: ('a, (string, t) => t) => option<string> = "JSON.stringify"
@@ -410,6 +486,7 @@ BigInt.fromInt(0)->JSON.stringifyAny
410486
- Raises a TypeError if the value contains circular references.
411487
- Raises a TypeError if the value contains `BigInt`s.
412488
*/
489+
@deprecated("Use `stringifyAny` with optional parameters instead")
413490
@raises
414491
@val
415492
external stringifyAnyWithReplacerAndIndent: ('a, (string, t) => t, int) => option<string> =
@@ -447,6 +524,7 @@ BigInt.fromInt(0)->JSON.stringifyAny
447524
- Raises a TypeError if the value contains circular references.
448525
- Raises a TypeError if the value contains `BigInt`s.
449526
*/
527+
@deprecated("Use `stringifyAny` with optional parameter instead")
450528
@raises
451529
@val
452530
external stringifyAnyWithFilter: ('a, array<string>) => string = "JSON.stringify"
@@ -486,6 +564,7 @@ BigInt.fromInt(0)->JSON.stringifyAny
486564
- Raises a TypeError if the value contains circular references.
487565
- Raises a TypeError if the value contains `BigInt`s.
488566
*/
567+
@deprecated("Use `stringifyAny` with optional parameters instead")
489568
@raises
490569
@val
491570
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)