What is lossless-json?
The lossless-json npm package allows for the parsing and stringifying of JSON data without losing precision for numbers. This is particularly useful for applications that require high precision in numerical data, such as financial calculations or scientific computations.
What are lossless-json's main functionalities?
Parse JSON without losing precision
This feature allows you to parse JSON strings containing large numbers without losing precision. The parsed numbers are represented as LosslessNumber objects.
{"const losslessJSON = require('lossless-json');":"","const jsonString = '{\"bigNumber\": 123456789012345678901234567890}';":"","const parsed = losslessJSON.parse(jsonString);":"","console.log(parsed.bigNumber.toString());":"// '123456789012345678901234567890'"}
Stringify JSON with high precision numbers
This feature allows you to stringify objects containing LosslessNumber instances, ensuring that the precision of large numbers is maintained in the resulting JSON string.
{"const losslessJSON = require('lossless-json');":"","const obj = { bigNumber: losslessJSON.LosslessNumber('123456789012345678901234567890') };":"","const jsonString = losslessJSON.stringify(obj);":"","console.log(jsonString);":"// '{\"bigNumber\":123456789012345678901234567890}'"}
Custom reviver and replacer functions
This feature allows you to use custom reviver and replacer functions during parsing and stringifying, providing more control over how data is processed.
{"const losslessJSON = require('lossless-json');":"","const jsonString = '{\"bigNumber\": 123456789012345678901234567890}';":"","const parsed = losslessJSON.parse(jsonString, (key, value) => {":""," if (typeof value === 'string' && !isNaN(value)) {":""," return losslessJSON.LosslessNumber(value);":""," }":""," return value;":"","});":"","console.log(parsed.bigNumber.toString());":"// '123456789012345678901234567890'"}
Other packages similar to lossless-json
bignumber.js
The bignumber.js package provides arbitrary-precision arithmetic for JavaScript. While it does not handle JSON parsing and stringifying directly, it can be used in conjunction with JSON.parse and JSON.stringify to manage large numbers. Unlike lossless-json, it requires manual handling of big numbers.
json-bigint
The json-bigint package is designed to handle JSON with large integers. It uses BigInt to parse and stringify JSON, ensuring that large numbers are not lost. However, it does not support custom reviver and replacer functions like lossless-json.
lossless-json
Parse JSON without risk of losing numeric information.
let text = '{"normal":2.3,"long":123456789012345678901,"big":2.3e+500}';
console.log(JSON.stringify(JSON.parse(text)));
console.log(LosslessJSON.stringify(LosslessJSON.parse(text)));
How does it work? The library works exactly the same as the native JSON.parse
and JSON.stringify
. The difference is that lossless-json
preserves information of big numbers. lossless-json
parses numeric values not as a regular number but as a LosslessNumber
, a data type which stores the numeric value as a string. One can perform regular operations with a LosslessNumber
, and it will throw an error when this would result in losing information.
When to use? Only in some special cases. For example when you have to create some sort of data processing middleware which has to process arbitrary JSON without risk of screwing up. JSON objects containing big numbers are rare in the wild. It can occur for example when interoperating with applications written in C++, Java, or C#, which support data types like long
. Parsing a long
into a JavaScript number
can result in losing information because a long
can hold more digits than a number
. If possible, it's preferable to change these applications such that they serialize big numbers in a safer way, for example in a stringified form. If that's not feasible, lossless-json
is here to help you out.
Features:
- No risk of losing numeric information when parsing JSON containing big numbers.
- Supports circular references.
- Compatible with the native
JSON.parse
and JSON.stringify
. - Works in browsers and node.js.
- Less then 3kB when minified and gzipped.
Install
Install via npm:
npm install lossless-json
Use
Parse and stringify
Parsing and stringification works as you're used to:
'use strict';
const LosslessJSON = require('lossless-json');
let json = LosslessJSON.parse('{"foo":"bar"}');
let text = LosslessJSON.stringify(json);
LosslessNumbers
Numbers are parsed into a LosslessNumber
, which can be used like a regular number in numeric operations. Converting to a number will throw an error when this would result in losing information due to truncation, overflow, or underflow.
'use strict';
const LosslessJSON = require('lossless-json');
let text = '{"normal":2.3,"long":123456789012345678901,"big":2.3e+500}';
let json = LosslessJSON.parse(text);
console.log(json.normal.isLosslessNumber);
console.log(json.normal.valueOf());
console.log(json.normal + 2);
console.log(json.long + 1);
console.log(json.big + 1);
If you want parse a json string into an object with regular numbers, but want to validate that no numeric information is lost, you can parse the json string using lossless-json
and immediately convert LosslessNumbers into numbers using a reviver:
'use strict';
const LosslessJSON = require('lossless-json');
function convertLosslessNumber (key, value) {
if (value && value.isLosslessNumber) {
return value.valueOf();
}
else {
return value;
}
}
let json = LosslessJSON.parse('[1,2,3]', convertLosslessNumber);
console.log(json);
try {
let json = LosslessJSON.parse('[1,2e+500,3]', convertLosslessNumber);
}
catch (err) {
console.log(err);
}
BigNumbers
To use the library in conjunction with your favorite BigNumber library, for example decimal.js, you can use a replacer and reviver:
'use strict';
const LosslessJSON = require('lossless-json');
const Decimal = require('decimal.js');
function reviver (key, value) {
if (value && value.isLosslessNumber) {
return new Decimal(value.toString());
}
else {
return value;
}
}
function replacer (key, value) {
if (value instanceof Decimal) {
return new LosslessJSON.LosslessNumber(value.toString());
}
else {
return value;
}
}
let text = '{"value":2.3e500}';
let json = LosslessJSON.parse(text, reviver);
let result = {
result: json.value.times(2)
};
let str = LosslessJSON.stringify(json, replacer);
Circular references
lossless-json
automatically stringifies and restores circular references. Circular references are encoded as a JSON Pointer URI fragment.
'use strict';
const LosslessJSON = require('lossless-json');
let json = {
foo: {
bar: {}
}
};
json.foo.bar.foo = json.foo;
let text = LosslessJSON.stringify(json);
When resolving circular references is not desirable, resolving circular references can be turned off:
'use strict';
const LosslessJSON = require('lossless-json');
LosslessJSON.config({circularRefs: false});
let json = {
foo: {
bar: {}
}
};
json.foo.bar.foo = json.foo;
try {
let text = LosslessJSON.stringify(json);
}
catch (err) {
console.log(err);
}
API
config([options])
Get and/or set configuration options for lossless-json
.
- @param
[{circularRefs: boolean}] [options]
Optional new configuration to be applied. - @returns
{{circularRefs}}
Returns an object with the current configuration.
The following options are available:
{boolean} circularRefs : true
When true
(default), LosslessJSON.stringify
will resolve circular references. When false
, the function will throw an error when a circular reference is encountered.
parse(text [, reviver])
The LosslessJSON.parse()
function parses a string as JSON, optionally transforming the value produced by parsing.
- @param
{string} text
The string to parse as JSON. See the JSON object for a description of JSON syntax. - @param
{function(key: string, value: *)} [reviver]
If a function, prescribes how the value originally produced by parsing is
- transformed, before being returned.
- @returns
{*}
Returns the Object corresponding to the given JSON text. - @throws Throws a SyntaxError exception if the string to parse is not valid JSON.
stringify(value [, replacer [, space]])
The `LosslessJSON.stringify()`` function converts a JavaScript value to a JSON string,
optionally replacing values if a replacer function is specified, or
optionally including only the specified properties if a replacer array is specified.
- @param
{*} value
The value to convert to a JSON string. - @param
{function(key: string, value: *) | Array.<string | number>} [replacer]
A function that alters the behavior of the stringification process,
or an array of String and Number objects that serve as a whitelist for
selecting the properties of the value object to be included in the JSON string.
If this value is null or not provided, all properties of the object are
included in the resulting JSON string. - @param
{number | string} [space]
A String or Number object that's used to insert white space into the output
JSON string for readability purposes. If this is a Number, it indicates the
number of space characters to use as white space; this number is capped at 10
if it's larger than that. Values less than 1 indicate that no space should be
used. If this is a String, the string (or the first 10 characters of the string,
if it's longer than that) is used as white space. If this parameter is not
provided (or is null), no white space is used. - @returns
{string | undefined}
Returns the string representation of the JSON object.
LosslessNumber
Construction
new LosslessJSON.LosslessNumber(value: number | string) : LosslessNumber
Methods
valueOf() : number
Convert the LosslessNumber to a regular number.
Throws an Error when this would result in loss of information: when the numbers digits would be truncated, or when the number would overflow or underflow.toString() : string
Get the string representation of the lossless number.
Properties
{boolean} isLosslessNumber : true
Lossless numbers contain a property isLosslessNumber
which can be used to
check whether some variable contains LosslessNumber.
Test
To test the library, first install dependencies once:
npm install
Then generate a bundle (some tests validate the created bundle):
npm run build
Then run the tests:
npm test
To run a benchmark to compare the performance with the native JSON
parser:
npm run benchmark
(Spoiler: lossless-json
is much slower than native)
Build
To build a bundled and minified library (ES5), first install the dependencies once:
npm install
Then bundle the code:
npm run build
This will generate an ES5 compatible bundle ./dist/lossless-json.js
which can be executed in browsers and node.js.
Deploy
- Update version number in
package.json
- Describe changes is
HISTORY.md
- run
npm test
to see whether everything works correctly. - merge changes from
develop
into master
- create git tag and push it:
git tag v1.0.2 && git push --tags
- publish via
npm publish
(this will first run npm test && npm run build
before actually publishing the library).
License
Released under the MIT license.