The `json()` function parses the given string value as JSON. Throws an exception if the given input value is not a string. Throws an exception if the given input string cannot be parsed as JSON. Returns the resulting value. -- Testcase -- {% print(join("\n", [ json("null"), json("true"), json("false"), json("123"), json("456.7890000"), json("-1.4E10"), json("1e309"), json('"A string \u2600"'), json("[ 1, 2, 3 ]"), json('{ "test": [ 1, 2, 3 ] }'), // surrounding white space is ignored json(' [ 1, 2, 3 ] ') ]), "\n"); %} -- End -- -- Expect stdout -- null true false 123 456.789 -14000000000 Infinity A string ☀ [ 1, 2, 3 ] { "test": [ 1, 2, 3 ] } [ 1, 2, 3 ] -- End -- Passing a non-string value throws an exception. -- Testcase -- {% json(true); %} -- End -- -- Expect stderr -- Type error: Passed value is neither a string nor an object In line 2, byte 11: ` json(true);` Near here ---^ -- End -- Unparseable JSON throws exceptions. -- Testcase -- {% json('[ "incomplete", "array" '); %} -- End -- -- Expect stderr -- Syntax error: Failed to parse JSON string: unexpected end of data In line 2, byte 33: ` json('[ "incomplete", "array" ');` Near here -------------------------^ -- End -- -- Testcase -- {% json('invalid syntax'); %} -- End -- -- Expect stderr -- Syntax error: Failed to parse JSON string: unexpected character In line 2, byte 23: ` json('invalid syntax');` Near here ---------------^ -- End -- -- Testcase -- {% json('[] trailing garbage'); %} -- End -- -- Expect stderr -- Syntax error: Trailing garbage after JSON data In line 2, byte 28: ` json('[] trailing garbage');` Near here --------------------^ -- End -- Additionally, `json()` accepts objects implementing a read method as input. During JSON parsing, the read method is repeatedly invoked with a buffer size hint as sole argument. The return value of the read method is converted to a string if needed and passed on to the JSON parser. A `null` or an empty string return value is treated as EOF, ending the parse process. -- Testcase -- {% let fs = require("fs"); // parse JSON from open file handle printf("%.J\n", json(fs.open("files/test.json")) ); %} -- End -- -- Expect stdout -- { "hello": "world" } -- End -- -- File test.json -- {"hello":"world"} -- End -- The `json()` function is able to parse JSON from any object providing a `read()` method that incrementally yields JSON source data. -- Testcase -- {% let parts = [ '{"some"', ':', '"object"', ', ', '"etc."', ':', !0, // this is stringified to "true" '}' ]; let producer = { read: function(size) { return shift(parts); } }; // parse JSON from producer object printf("%.J\n", json(producer) ); %} -- End -- -- Expect stdout -- { "some": "object", "etc.": true } -- End -- Passing objects or resources not providing a `read()` method yields an exception. -- Testcase -- {% json({}); %} -- End -- -- Expect stderr -- Type error: Input object does not implement read() method In line 2, byte 9: ` json({});` Near here -^ -- End -- Exceptions triggered by the `read()` method are properly forwarded. -- Testcase -- {% json({ read: function() { die("Exception in read()"); } }); %} -- End -- -- Expect stderr -- Exception in read() In [anonymous function](), line 4, byte 29: called from function json ([C]) called from anonymous function ([stdin]:6:3) ` die("Exception in read()");` Near here ---------------------------^ -- End -- EOF stops parsing and does not lead to further `read()` invocations. -- Testcase -- {% let parts = [ '["some",', '"JSON array",', 'true,false,1,2,3', ']', '', // empty string treated as EOF '{"some":', // this is not reached in the first pass '"object"}', null, // null treated as EOF '"test ', // this is not reached in the second pass 'value"' ]; let producer = { read: () => shift(parts) }; printf("%.J\n", [ json(producer), json(producer), json(producer) ]); %} -- End -- -- Expect stdout -- [ [ "some", "JSON array", true, false, 1, 2, 3 ], { "some": "object" }, "test value" ] -- End --