Socket
Socket
Sign inDemoInstall

lossless-json

Package Overview
Dependencies
Maintainers
1
Versions
27
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

lossless-json - npm Package Compare versions

Comparing version 4.0.1 to 4.0.2

3

lib/esm/config.js

@@ -5,4 +5,3 @@ /**

*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function config(options) {
export function config(_options) {
// Backward compatibility warning for v1.x

@@ -9,0 +8,0 @@ throw new Error('config is deprecated, support for circularRefs is removed from the library. ' + 'If you encounter circular references in your data structures, ' + 'please rethink your datastructures: ' + 'better prevent circular references in the first place.');

@@ -1,4 +0,4 @@

import { test, expect } from 'vitest';
import { getUnsafeNumberReason, isInteger, isLosslessNumber, isNumber, isSafeNumber, LosslessNumber, parse, parseLosslessNumber, parseNumberAndBigInt, reviveDate, stringify, toLosslessNumber, toSafeNumberOrThrow } from './index';
test('Public API', function () {
import { expect, test } from 'vitest';
import { LosslessNumber, getUnsafeNumberReason, isInteger, isLosslessNumber, isNumber, isSafeNumber, parse, parseLosslessNumber, parseNumberAndBigInt, reviveDate, stringify, toLosslessNumber, toSafeNumberOrThrow } from './index';
test('Public API', () => {
expect(parse('{}')).toEqual({});

@@ -5,0 +5,0 @@ expect(stringify({})).toEqual('{}');

@@ -1,2 +0,2 @@

import { extractSignificantDigits, getUnsafeNumberReason, isInteger, isNumber, UnsafeNumberReason } from './utils.js';
import { UnsafeNumberReason, extractSignificantDigits, getUnsafeNumberReason, isInteger, isNumber } from './utils.js';

@@ -13,3 +13,3 @@ /**

if (!isNumber(value)) {
throw new Error('Invalid number (value: "' + value + '")');
throw new Error(`Invalid number (value: "${value}")`);
}

@@ -35,3 +35,3 @@ this.value = value;

if (unsafeReason === undefined || unsafeReason === UnsafeNumberReason.truncate_float) {
return parseFloat(this.value);
return Number.parseFloat(this.value);
}

@@ -45,3 +45,3 @@

// overflow or underflow
throw new Error('Cannot safely convert to number: ' + `the value '${this.value}' would ${unsafeReason} and become ${parseFloat(this.value)}`);
throw new Error(`Cannot safely convert to number: the value '${this.value}' would ${unsafeReason} and become ${Number.parseFloat(this.value)}`);
}

@@ -65,3 +65,2 @@

export function isLosslessNumber(value) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore

@@ -76,10 +75,10 @@ return value && typeof value === 'object' && value.isLosslessNumber === true || false;

export function toLosslessNumber(value) {
if (extractSignificantDigits(value + '').length > 15) {
throw new Error('Invalid number: contains more than 15 digits and is most likely truncated and unsafe by itself ' + `(value: ${value})`);
if (extractSignificantDigits(String(value)).length > 15) {
throw new Error(`Invalid number: contains more than 15 digits and is most likely truncated and unsafe by itself (value: ${value})`);
}
if (isNaN(value)) {
if (Number.isNaN(value)) {
throw new Error('Invalid number: NaN');
}
if (!isFinite(value)) {
throw new Error('Invalid number: ' + value);
if (!Number.isFinite(value)) {
throw new Error(`Invalid number: ${value}`);
}

@@ -86,0 +85,0 @@ return new LosslessNumber(String(value));

@@ -1,4 +0,4 @@

import { test, expect } from 'vitest';
import { isLosslessNumber, LosslessNumber, toLosslessNumber } from './index';
test('create a LosslessNumber from string', function () {
import { expect, test } from 'vitest';
import { LosslessNumber, isLosslessNumber, toLosslessNumber } from './index';
test('create a LosslessNumber from string', () => {
const n = new LosslessNumber('42');

@@ -8,3 +8,3 @@ expect(n.isLosslessNumber).toBe(true);

});
test('throw an error when when creating a LosslessNumber from invalid string', function () {
test('throw an error when when creating a LosslessNumber from invalid string', () => {
// invalid

@@ -25,3 +25,3 @@ expect(() => new LosslessNumber('a')).toThrow(/Invalid number/);

});
test('test whether something is a LosslessNumber', function () {
test('test whether something is a LosslessNumber', () => {
const n = new LosslessNumber('42');

@@ -35,11 +35,11 @@ expect(isLosslessNumber(n)).toBe(true);

});
test('create a LosslessNumber from number', function () {
test('create a LosslessNumber from number', () => {
expect(toLosslessNumber(42)).toEqual(new LosslessNumber('42'));
expect(toLosslessNumber(2.47)).toEqual(new LosslessNumber('2.47'));
expect(() => toLosslessNumber(2 / 3)).toThrow('Invalid number: contains more than 15 digits');
expect(() => toLosslessNumber(NaN)).toThrow('Invalid number: NaN');
expect(() => toLosslessNumber(Infinity)).toThrow('Invalid number: Infinity');
expect(() => toLosslessNumber(-Infinity)).toThrow('Invalid number: -Infinity');
expect(() => toLosslessNumber(Number.NaN)).toThrow('Invalid number: NaN');
expect(() => toLosslessNumber(Number.POSITIVE_INFINITY)).toThrow('Invalid number: Infinity');
expect(() => toLosslessNumber(Number.NEGATIVE_INFINITY)).toThrow('Invalid number: -Infinity');
});
test('use LosslessNumber.valueOf()', function () {
test('use LosslessNumber.valueOf()', () => {
// safe number

@@ -62,9 +62,8 @@ expect(new LosslessNumber('23.4').valueOf()).toBe(23.4);

test('can do operations like add a number and a LosslessNumber', () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
expect(new LosslessNumber('3') + 2).toBe(5);
});
test('LosslessNumber - toString', function () {
test('LosslessNumber - toString', () => {
expect(new LosslessNumber('23.4').toString()).toBe('23.4');
});
//# sourceMappingURL=LosslessNumber.test.js.map

@@ -7,4 +7,4 @@ import { LosslessNumber } from './LosslessNumber.js';

export function parseNumberAndBigInt(value) {
return isInteger(value) ? BigInt(value) : parseFloat(value);
return isInteger(value) ? BigInt(value) : Number.parseFloat(value);
}
//# sourceMappingURL=numberParsers.js.map

@@ -127,3 +127,3 @@ import { parseLosslessNumber } from './numberParsers.js';

if (isHex(text.charCodeAt(i + 2)) && isHex(text.charCodeAt(i + 3)) && isHex(text.charCodeAt(i + 4)) && isHex(text.charCodeAt(i + 5))) {
result += String.fromCharCode(parseInt(text.slice(i + 2, i + 6), 16));
result += String.fromCharCode(Number.parseInt(text.slice(i + 2, i + 6), 16));
i += 5;

@@ -258,3 +258,3 @@ } else {

function gotAt() {
return got() + ' ' + pos();
return `${got()} ${pos()}`;
}

@@ -261,0 +261,0 @@ }

@@ -1,6 +0,5 @@

import { describe, test, expect } from 'vitest';
import Decimal from 'decimal.js';
import { isLosslessNumber, LosslessNumber, parse, parseNumberAndBigInt, reviveDate, stringify } from './index';
import { describe, expect, test } from 'vitest';
import { LosslessNumber, isLosslessNumber, parse, parseNumberAndBigInt, reviveDate, stringify } from './index';
import { isDeepEqual } from './parse';
// helper function to create a lossless number

@@ -20,3 +19,3 @@ function lln(value) {

}
test('full JSON object', function () {
test('full JSON object', () => {
const text = '{"a":2.3e100,"b":"str","c":null,"d":false,"e":[1,2,3]}';

@@ -33,3 +32,3 @@ const expected = {

});
test('object', function () {
test('object', () => {
expect(parse('{}')).toEqual({});

@@ -47,3 +46,3 @@ expect(parse(' { \n } \t ')).toEqual({});

});
test('array', function () {
test('array', () => {
expect(parse('[]')).toEqual([]);

@@ -56,3 +55,3 @@ expect(parse('[{}]')).toEqual([{}]);

});
test('number', function () {
test('number', () => {
expect(isLosslessNumber(parse('2.3e500'))).toBe(true);

@@ -73,3 +72,3 @@ expect(isLosslessNumber(parse('123456789012345678901234567890'))).toBe(true);

});
test('LosslessNumber', function () {
test('LosslessNumber', () => {
const str = '22222222222222222222';

@@ -82,3 +81,3 @@ expectDeepEqual(parse(str), lln(str));

});
test('string', function () {
test('string', () => {
expect(parse('"str"')).toEqual('str');

@@ -90,3 +89,3 @@ expect(JSON.parse('"\\"\\\\\\/\\b\\f\\n\\r\\t"')).toEqual('"\\/\b\f\n\r\t');

});
test('keywords', function () {
test('keywords', () => {
expect(parse('true')).toEqual(true);

@@ -96,3 +95,3 @@ expect(parse('false')).toEqual(false);

});
test('reviver - replace values', function () {
test('reviver - replace values', () => {
const text = '{"a":123,"b":"str"}';

@@ -112,3 +111,3 @@ const expected = {

};
function reviver(key, value) {
function reviver(_key, value) {
return {

@@ -121,3 +120,3 @@ type: typeof value,

});
test('reviver - invoke callbacks with key/value and correct context', function () {
test('reviver - invoke callbacks with key/value and correct context', () => {
const text = '{"a":123,"b":"str","c":null,"22":22,"d":false,"e":[1,2,3]}';

@@ -244,3 +243,2 @@ const expected = [{

logsActual.push({
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error

@@ -256,3 +254,3 @@ context: toRegularJSON(this),

});
test('correctly handle strings equaling a JSON delimiter', function () {
test('correctly handle strings equaling a JSON delimiter', () => {
expect(parse('""')).toEqual('');

@@ -266,3 +264,3 @@ expect(parse('"["')).toEqual('[');

});
test('reviver - revive a lossless number correctly', function () {
test('reviver - revive a lossless number correctly', () => {
const text = '2.3e+500';

@@ -274,3 +272,3 @@ const expected = [{

const logs = [];
parse(text, function (key, value) {
parse(text, (key, value) => {
logs.push({

@@ -356,3 +354,3 @@ key,

});
expect(parse('{"scores": [2.3, 7.1], "scores": [2.3, 7.1]}', null, parseFloat)).toStrictEqual({
expect(parse('{"scores": [2.3, 7.1], "scores": [2.3, 7.1]}', null, Number.parseFloat)).toStrictEqual({
scores: [2.3, 7.1]

@@ -453,11 +451,10 @@ });

}];
cases.forEach(_ref => {
let {
input,
expectedError
} = _ref;
for (const {
input,
expectedError
} of cases) {
test(`should throw when parsing '${input}'`, () => {
expect(() => parse(input)).toThrow(expectedError);
});
});
}
});

@@ -464,0 +461,0 @@ describe('isDeepEqual', () => {

@@ -24,9 +24,9 @@ import { isLosslessNumber } from './LosslessNumber.js';

return reviver.call(context, key, reviveArray(value, reviver));
} else if (value && typeof value === 'object' && !isLosslessNumber(value)) {
}
if (value && typeof value === 'object' && !isLosslessNumber(value)) {
// note the special case for LosslessNumber,
// we don't want to iterate over the internals of a LosslessNumber
return reviver.call(context, key, reviveObject(value, reviver));
} else {
return reviver.call(context, key, value);
}
return reviver.call(context, key, value);
}

@@ -38,3 +38,3 @@

function reviveObject(object, reviver) {
Object.keys(object).forEach(key => {
for (const key of Object.keys(object)) {
const value = reviveValue(object, key, object[key], reviver);

@@ -46,3 +46,3 @@ if (value !== undefined) {

}
});
}
return object;

@@ -56,3 +56,3 @@ }

for (let i = 0; i < array.length; i++) {
array[i] = reviveValue(array, i + '', array[i], reviver);
array[i] = reviveValue(array, String(i), array[i], reviver);
}

@@ -59,0 +59,0 @@ return array;

@@ -53,3 +53,3 @@ import { isNumber } from './utils.js';

if (typeof str !== 'string' || !isNumber(str)) {
throw new Error('Invalid JSON number: ' + 'output of a number stringifier must be a string containing a JSON number ' + `(output: ${str})`);
throw new Error(`Invalid JSON number: output of a number stringifier must be a string containing a JSON number (output: ${str})`);
}

@@ -66,5 +66,4 @@ return str;

// lossless number, the secret ingredient :)
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (value && value.isLosslessNumber) {
if (value?.isLosslessNumber) {
return value.toString();

@@ -113,3 +112,3 @@ }

}
str += resolvedSpace ? '\n' + indent + ']' : ']';
str += resolvedSpace ? `\n${indent}]` : ']';
return str;

@@ -132,3 +131,3 @@ }

let str = resolvedSpace ? '{\n' : '{';
keys.forEach(key => {
for (const key of keys) {
const value = typeof replacer === 'function' ? replacer.call(object, key, object[key]) : object[key];

@@ -142,7 +141,7 @@ if (includeProperty(key, value)) {

const keyStr = JSON.stringify(key);
str += resolvedSpace ? childIndent + keyStr + ': ' : keyStr + ':';
str += resolvedSpace ? `${childIndent + keyStr}: ` : `${keyStr}:`;
str += stringifyValue(value, childIndent);
}
});
str += resolvedSpace ? '\n' + indent + '}' : '}';
}
str += resolvedSpace ? `\n${indent}}` : '}';
return str;

@@ -154,3 +153,3 @@ }

*/
function includeProperty(key, value) {
function includeProperty(_key, value) {
return typeof value !== 'undefined' && typeof value !== 'function' && typeof value !== 'symbol';

@@ -157,0 +156,0 @@ }

@@ -1,3 +0,3 @@

import { test, expect } from 'vitest';
import Decimal from 'decimal.js';
import { expect, test } from 'vitest';
import { LosslessNumber, stringify } from './index';

@@ -8,5 +8,5 @@ // helper function to create a lossless number

}
test('stringify', function () {
test('stringify', () => {
expect(stringify(undefined)).toEqual(undefined);
expect(stringify(function () {})).toEqual(undefined);
expect(stringify(() => {})).toEqual(undefined);
expect(stringify(Symbol('test'))).toEqual(undefined);

@@ -16,14 +16,10 @@ expect(stringify(null)).toEqual('null');

expect(stringify(false)).toEqual('false');
// eslint-disable-next-line no-new-wrappers
expect(stringify(new Boolean(true))).toEqual('true');
// eslint-disable-next-line no-new-wrappers
expect(stringify(new Boolean(false))).toEqual('false');
expect(stringify(2.3)).toEqual('2.3');
// eslint-disable-next-line no-new-wrappers
expect(stringify(new Number(2.3))).toEqual('2.3');
expect(stringify(-2.3)).toEqual('-2.3');
expect(stringify(Infinity)).toEqual('null');
expect(stringify(NaN)).toEqual('null');
expect(stringify(Number.POSITIVE_INFINITY)).toEqual('null');
expect(stringify(Number.NaN)).toEqual('null');
expect(stringify('str')).toEqual('"str"');
// eslint-disable-next-line no-new-wrappers
expect(stringify(new String('str'))).toEqual('"str"');

@@ -42,3 +38,3 @@ expect(stringify('"')).toEqual('"\\""');

expect(stringify(new Date('2016-02-08T14:00:00Z'))).toEqual('"2016-02-08T14:00:00.000Z"');
expect(stringify([2, 'str', null, undefined, true, function () {
expect(stringify([2, 'str', null, undefined, true, () => {
console.log('test');

@@ -51,3 +47,3 @@ }])).toEqual('[2,"str",null,null,true,null]');

d: undefined,
e: function () {
e: () => {
console.log('test');

@@ -66,5 +62,3 @@ }

a: 2,
toJSON: function () {
return 'foo';
}
toJSON: () => 'foo'
})).toEqual('"foo"');

@@ -75,3 +69,3 @@

});
test('stringify a full JSON object', function () {
test('stringify a full JSON object', () => {
const expected = '{"a":123,"b":"str","c":null,"d":false,"e":[1,2,3]}';

@@ -88,3 +82,3 @@ const json = {

});
test('stringify bigint', function () {
test('stringify bigint', () => {
expect(stringify(123n)).toEqual('123');

@@ -95,6 +89,6 @@ expect(stringify({

});
test('stringify Date', function () {
test('stringify Date', () => {
expect(stringify([new Date('2022-08-25T09:39:19.288Z')])).toEqual('["2022-08-25T09:39:19.288Z"]');
});
test('stringify Decimal', function () {
test('stringify Decimal', () => {
const decimalStringifier = {

@@ -110,16 +104,16 @@ test: value => Decimal.isDecimal(value),

});
test('should not have a .toJSON method implemented', function () {
test('should not have a .toJSON method implemented', () => {
expect('toJSON' in lln('123')).toBe(false);
});
test('should throw an error when the output of a number stringifier is not a number', function () {
test('should throw an error when the output of a number stringifier is not a number', () => {
const wrongStringifier = {
test: value => typeof value === 'number',
stringify: value => 'oopsie' + value // <-- does not return a valid number
stringify: value => `oopsie${value}` // <-- does not return a valid number
};
expect(() => stringify([4], undefined, undefined, [wrongStringifier])).toThrow('Invalid JSON number: output of a number stringifier must be a string containing a JSON number (output: oopsie4)');
});
test('stringify should keep formatting of a lossless number', function () {
test('stringify should keep formatting of a lossless number', () => {
expect(stringify([lln('4.0')])).toEqual('[4.0]');
});
test('stringify with replacer function', function () {
test('stringify with replacer function', () => {
const json = {

@@ -215,3 +209,2 @@ a: 123,

stringify(json, function (key, value) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error

@@ -239,3 +232,3 @@ logs.push({

});
test('stringify with replacer function (2)', function () {
test('stringify with replacer function (2)', () => {
const json = {

@@ -252,6 +245,6 @@ a: 123,

if (typeof value === 'number') {
return 'number:' + key + ':' + value;
return `number:${key}:${value}`;
}
if (typeof value === 'string') {
return 'string:' + key + ':' + value;
return `string:${key}:${value}`;
}

@@ -265,3 +258,3 @@ return value;

});
test('stringify with replacer Array', function () {
test('stringify with replacer Array', () => {
const json = {

@@ -286,3 +279,3 @@ a: 1,

});
test('stringify with numeric space', function () {
test('stringify with numeric space', () => {
const json = {

@@ -301,3 +294,3 @@ a: 1,

});
test('stringify with string space', function () {
test('stringify with string space', () => {
const json = {

@@ -316,7 +309,7 @@ a: 1,

});
test('stringify an empty array', function () {
test('stringify an empty array', () => {
expect(stringify([], null, 2)).toEqual('[]');
expect(stringify([], null, ' ')).toEqual('[]');
});
test('stringify an empty object', function () {
test('stringify an empty object', () => {
expect(stringify({}, null, 2)).toEqual('{}');

@@ -323,0 +316,0 @@ expect(stringify({}, null, ' ')).toEqual('{}');

@@ -27,3 +27,3 @@ /**

export function isSafeNumber(value, config) {
const num = parseFloat(value);
const num = Number.parseFloat(value);
const str = String(num);

@@ -69,4 +69,4 @@ const v = extractSignificantDigits(value);

}
const num = parseFloat(value);
if (!isFinite(num)) {
const num = Number.parseFloat(value);
if (!Number.isFinite(num)) {
return UnsafeNumberReason.overflow;

@@ -85,7 +85,7 @@ }

export function toSafeNumberOrThrow(value, config) {
const number = parseFloat(value);
const number = Number.parseFloat(value);
const unsafeReason = getUnsafeNumberReason(value);
if (config?.approx === true ? unsafeReason && unsafeReason !== UnsafeNumberReason.truncate_float : unsafeReason) {
const unsafeReasonText = unsafeReason?.replace(/_\w+$/, '');
throw new Error('Cannot safely convert to number: ' + `the value '${value}' would ${unsafeReasonText} and become ${number}`);
throw new Error(`Cannot safely convert to number: the value '${value}' would ${unsafeReasonText} and become ${number}`);
}

@@ -92,0 +92,0 @@ return number;

@@ -1,3 +0,3 @@

import { test, expect } from 'vitest';
import { extractSignificantDigits, getUnsafeNumberReason, isInteger, isNumber, isSafeNumber, toSafeNumberOrThrow, UnsafeNumberReason } from './utils';
import { expect, test } from 'vitest';
import { UnsafeNumberReason, extractSignificantDigits, getUnsafeNumberReason, isInteger, isNumber, isSafeNumber, toSafeNumberOrThrow } from './utils';
test('isInteger', () => {

@@ -4,0 +4,0 @@ expect(isInteger('4250')).toEqual(true);

@@ -11,4 +11,4 @@ interface ConfigOptional {

*/
export declare function config(options?: ConfigOptional): Config;
export declare function config(_options?: ConfigOptional): Config;
export {};
//# sourceMappingURL=config.d.ts.map

@@ -1,1 +0,1 @@

!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).LosslessJSON={})}(this,(function(t){"use strict";function e(t){return r.test(t)}const r=/^-?[0-9]+$/;function n(t){return o.test(t)}const o=/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/;function i(t,r){const n=parseFloat(t),o=String(n),i=a(t),c=a(o);if(i===c)return!0;if(!0===r?.approx){const r=14;if(!e(t)&&c.length>=r&&i.startsWith(c.substring(0,r)))return!0}return!1}let c=function(t){return t.underflow="underflow",t.overflow="overflow",t.truncate_integer="truncate_integer",t.truncate_float="truncate_float",t}({});function u(t){if(i(t,{approx:!1}))return;if(e(t))return c.truncate_integer;const r=parseFloat(t);return isFinite(r)?0===r?c.underflow:c.truncate_float:c.overflow}function a(t){return t.replace(f,"").replace(l,"").replace(d,"").replace(s,"")}const f=/[eE][+-]?\d+$/,s=/^-?(0*)?/,l=/\./,d=/0+$/;class h{isLosslessNumber=!0;constructor(t){if(!n(t))throw new Error('Invalid number (value: "'+t+'")');this.value=t}valueOf(){const t=u(this.value);if(void 0===t||t===c.truncate_float)return parseFloat(this.value);if(e(this.value))return BigInt(this.value);throw new Error(`Cannot safely convert to number: the value '${this.value}' would ${t} and become ${parseFloat(this.value)}`)}toString(){return this.value}}function p(t){return t&&"object"==typeof t&&!0===t.isLosslessNumber||!1}function y(t){return new h(t)}function w(t,e,r,n){return Array.isArray(r)?n.call(t,e,function(t,e){for(let r=0;r<t.length;r++)t[r]=w(t,r+"",t[r],e);return t}(r,n)):r&&"object"==typeof r&&!p(r)?n.call(t,e,function(t,e){return Object.keys(t).forEach((r=>{const n=w(t,r,t[r],e);void 0!==n?t[r]=n:delete t[r]})),t}(r,n)):n.call(t,e,r)}function b(t){return t>=J&&t<=B||t>=Q&&t<=Z||t>=U&&t<=q}function g(t){return t>=J&&t<=B}function v(t,e){if(t===e)return!0;if(Array.isArray(t)&&Array.isArray(e))return t.length===e.length&&t.every(((t,r)=>v(t,e[r])));if(A(t)&&A(e)){return[...new Set([...Object.keys(t),...Object.keys(e)])].every((r=>v(t[r],e[r])))}return!1}function A(t){return"object"==typeof t&&null!==t}const m={'"':'"',"\\":"\\","/":"/",b:"\b",f:"\f",n:"\n",r:"\r",t:"\t"},C=92,$=123,S=125,x=91,E=93,N=32,O=10,I=9,j=13,k=34,_=43,F=45,J=48,L=49,B=57,D=44,T=46,R=58,Q=65,U=97,P=69,W=101,Z=70,q=102;const z=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;t.LosslessNumber=h,t.UnsafeNumberReason=c,t.config=function(t){throw new Error("config is deprecated, support for circularRefs is removed from the library. If you encounter circular references in your data structures, please rethink your datastructures: better prevent circular references in the first place.")},t.getUnsafeNumberReason=u,t.isInteger=e,t.isLosslessNumber=p,t.isNumber=n,t.isSafeNumber=i,t.parse=function(t,e){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:y,n=0;const o=u();return function(t){if(void 0===t)throw new SyntaxError(`JSON value expected ${H()}`)}(o),function(){if(n<t.length)throw new SyntaxError(`Expected end of input ${H()}`)}(),e?function(t,e){return w({"":t},"",t,e)}(o,e):o;function i(){if(t.charCodeAt(n)===$){n++,f();const e={};let r=!0;for(;n<t.length&&t.charCodeAt(n)!==S;){r?r=!1:(l(),f());const t=n,o=s();if(void 0===o)return void A();f(),d();const i=u();if(void 0===i)return void q();Object.prototype.hasOwnProperty.call(e,o)&&!v(i,e[o])&&Q(o,t+1),e[o]=i}return t.charCodeAt(n)!==S&&function(){throw new SyntaxError(`Quoted object key or end of object '}' expected ${H()}`)}(),n++,e}}function c(){if(t.charCodeAt(n)===x){n++,f();const e=[];let r=!0;for(;n<t.length&&t.charCodeAt(n)!==E;){r?r=!1:l();const t=u();h(t),e.push(t)}return t.charCodeAt(n)!==E&&function(){throw new SyntaxError(`Array item or end of array ']' expected ${H()}`)}(),n++,e}}function u(){f();const e=s()??function(){const e=n;t.charCodeAt(n)===F&&(n++,p(e));if(t.charCodeAt(n)===J)n++;else if(o=t.charCodeAt(n),o>=L&&o<=B)for(n++;g(t.charCodeAt(n));)n++;var o;if(t.charCodeAt(n)===T)for(n++,p(e);g(t.charCodeAt(n));)n++;if(t.charCodeAt(n)===W||t.charCodeAt(n)===P)for(n++,t.charCodeAt(n)!==F&&t.charCodeAt(n)!==_||n++,p(e);g(t.charCodeAt(n));)n++;if(n>e)return r(t.slice(e,n))}()??i()??c()??a("true",!0)??a("false",!1)??a("null",null);return f(),e}function a(e,r){if(t.slice(n,n+e.length)===e)return n+=e.length,r}function f(){for(;(e=t.charCodeAt(n))===N||e===O||e===I||e===j;)n++;var e}function s(){if(t.charCodeAt(n)===k){n++;let r="";for(;n<t.length&&t.charCodeAt(n)!==k;){if(t.charCodeAt(n)===C){const e=t[n+1],o=m[e];void 0!==o?(r+=o,n++):"u"===e?b(t.charCodeAt(n+2))&&b(t.charCodeAt(n+3))&&b(t.charCodeAt(n+4))&&b(t.charCodeAt(n+5))?(r+=String.fromCharCode(parseInt(t.slice(n+2,n+6),16)),n+=5):z(n):Z(n)}else(e=t.charCodeAt(n))>=32&&e<=1114111?r+=t[n]:U(t[n]);n++}return function(){if(t.charCodeAt(n)!==k)throw new SyntaxError(`End of string '"' expected ${H()}`)}(),n++,r}var e}function l(){if(t.charCodeAt(n)!==D)throw new SyntaxError(`Comma ',' expected after value ${H()}`);n++}function d(){if(t.charCodeAt(n)!==R)throw new SyntaxError(`Colon ':' expected after property name ${H()}`);n++}function h(t){if(void 0===t)throw new SyntaxError(`Array item expected ${H()}`)}function p(e){if(!g(t.charCodeAt(n))){const r=t.slice(e,n);throw new SyntaxError(`Invalid number '${r}', expecting a digit ${H()}`)}}function A(){throw new SyntaxError(`Quoted object key expected ${H()}`)}function Q(t,e){throw new SyntaxError(`Duplicate key '${t}' encountered at position ${e}`)}function U(t){throw new SyntaxError(`Invalid character '${t}' ${G()}`)}function Z(e){const r=t.slice(e,e+2);throw new SyntaxError(`Invalid escape character '${r}' ${G()}`)}function q(){throw new SyntaxError(`Object value expected after ':' ${G()}`)}function z(e){const r=t.slice(e,e+6);throw new SyntaxError(`Invalid unicode character '${r}' ${G()}`)}function G(){return`at position ${n}`}function H(){return(n<t.length?`but got '${t[n]}'`:"but reached end of input")+" "+G()}},t.parseLosslessNumber=y,t.parseNumberAndBigInt=function(t){return e(t)?BigInt(t):parseFloat(t)},t.reviveDate=function(t,e){return"string"==typeof e&&z.test(e)?new Date(e):e},t.stringify=function t(e,r,o,i){const c=function(t){if("number"==typeof t)return" ".repeat(t);if("string"==typeof t&&""!==t)return t;return}(o);return u("function"==typeof r?r.call({"":e},"",e):e,"");function u(e,a){if(Array.isArray(i)){const t=i.find((t=>t.test(e)));if(t){const r=t.stringify(e);if("string"!=typeof r||!n(r))throw new Error(`Invalid JSON number: output of a number stringifier must be a string containing a JSON number (output: ${r})`);return r}}return"boolean"==typeof e||"number"==typeof e||"string"==typeof e||null===e||e instanceof Date||e instanceof Boolean||e instanceof Number||e instanceof String?JSON.stringify(e):e&&e.isLosslessNumber||"bigint"==typeof e?e.toString():Array.isArray(e)?function(t,e){if(0===t.length)return"[]";const n=c?e+c:void 0;let o=c?"[\n":"[";for(let e=0;e<t.length;e++){const i="function"==typeof r?r.call(t,String(e),t[e]):t[e];c&&(o+=n),o+=void 0!==i&&"function"!=typeof i?u(i,n):"null",e<t.length-1&&(o+=c?",\n":",")}return o+=c?"\n"+e+"]":"]",o}(e,a):e&&"object"==typeof e?function(e,n){if("function"==typeof e.toJSON)return t(e.toJSON(),r,o,void 0);const i=Array.isArray(r)?r.map(String):Object.keys(e);if(0===i.length)return"{}";const a=c?n+c:void 0;let f=!0,s=c?"{\n":"{";return i.forEach((t=>{const n="function"==typeof r?r.call(e,t,e[t]):e[t];if(function(t,e){return void 0!==e&&"function"!=typeof e&&"symbol"!=typeof e}(0,n)){f?f=!1:s+=c?",\n":",";const e=JSON.stringify(t);s+=c?a+e+": ":e+":",s+=u(n,a)}})),s+=c?"\n"+n+"}":"}",s}(e,a):void 0}},t.toLosslessNumber=function(t){if(a(t+"").length>15)throw new Error(`Invalid number: contains more than 15 digits and is most likely truncated and unsafe by itself (value: ${t})`);if(isNaN(t))throw new Error("Invalid number: NaN");if(!isFinite(t))throw new Error("Invalid number: "+t);return new h(String(t))},t.toSafeNumberOrThrow=function(t,e){const r=parseFloat(t),n=u(t);if(!0===e?.approx?n&&n!==c.truncate_float:n){const e=n?.replace(/_\w+$/,"");throw new Error(`Cannot safely convert to number: the value '${t}' would ${e} and become ${r}`)}return r}}));//# sourceMappingURL=lossless-json.js.map
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).LosslessJSON={})}(this,(function(t){"use strict";function e(t){return r.test(t)}const r=/^-?[0-9]+$/;function n(t){return o.test(t)}const o=/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/;function i(t,r){const n=Number.parseFloat(t),o=String(n),i=a(t),u=a(o);if(i===u)return!0;if(!0===r?.approx){const r=14;if(!e(t)&&u.length>=r&&i.startsWith(u.substring(0,r)))return!0}return!1}let u=function(t){return t.underflow="underflow",t.overflow="overflow",t.truncate_integer="truncate_integer",t.truncate_float="truncate_float",t}({});function c(t){if(i(t,{approx:!1}))return;if(e(t))return u.truncate_integer;const r=Number.parseFloat(t);return Number.isFinite(r)?0===r?u.underflow:u.truncate_float:u.overflow}function a(t){return t.replace(f,"").replace(l,"").replace(d,"").replace(s,"")}const f=/[eE][+-]?\d+$/,s=/^-?(0*)?/,l=/\./,d=/0+$/;class h{isLosslessNumber=!0;constructor(t){if(!n(t))throw new Error(`Invalid number (value: "${t}")`);this.value=t}valueOf(){const t=c(this.value);if(void 0===t||t===u.truncate_float)return Number.parseFloat(this.value);if(e(this.value))return BigInt(this.value);throw new Error(`Cannot safely convert to number: the value '${this.value}' would ${t} and become ${Number.parseFloat(this.value)}`)}toString(){return this.value}}function p(t){return t&&"object"==typeof t&&!0===t.isLosslessNumber||!1}function y(t){return new h(t)}function b(t,e,r,n){return Array.isArray(r)?n.call(t,e,function(t,e){for(let r=0;r<t.length;r++)t[r]=b(t,String(r),t[r],e);return t}(r,n)):r&&"object"==typeof r&&!p(r)?n.call(t,e,function(t,e){for(const r of Object.keys(t)){const n=b(t,r,t[r],e);void 0!==n?t[r]=n:delete t[r]}return t}(r,n)):n.call(t,e,r)}function w(t){return t>=J&&t<=B||t>=Q&&t<=Z||t>=U&&t<=q}function g(t){return t>=J&&t<=B}function v(t,e){if(t===e)return!0;if(Array.isArray(t)&&Array.isArray(e))return t.length===e.length&&t.every(((t,r)=>v(t,e[r])));if(m(t)&&m(e)){return[...new Set([...Object.keys(t),...Object.keys(e)])].every((r=>v(t[r],e[r])))}return!1}function m(t){return"object"==typeof t&&null!==t}const A={'"':'"',"\\":"\\","/":"/",b:"\b",f:"\f",n:"\n",r:"\r",t:"\t"},$=92,C=123,N=125,S=91,x=93,E=32,O=10,I=9,j=13,k=34,_=43,F=45,J=48,L=49,B=57,D=44,T=46,R=58,Q=65,U=97,P=69,W=101,Z=70,q=102;const z=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;t.LosslessNumber=h,t.UnsafeNumberReason=u,t.config=function(t){throw new Error("config is deprecated, support for circularRefs is removed from the library. If you encounter circular references in your data structures, please rethink your datastructures: better prevent circular references in the first place.")},t.getUnsafeNumberReason=c,t.isInteger=e,t.isLosslessNumber=p,t.isNumber=n,t.isSafeNumber=i,t.parse=function(t,e){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:y,n=0;const o=c();return function(t){if(void 0===t)throw new SyntaxError(`JSON value expected ${H()}`)}(o),function(){if(n<t.length)throw new SyntaxError(`Expected end of input ${H()}`)}(),e?function(t,e){return b({"":t},"",t,e)}(o,e):o;function i(){if(t.charCodeAt(n)===C){n++,f();const e={};let r=!0;for(;n<t.length&&t.charCodeAt(n)!==N;){r?r=!1:(l(),f());const t=n,o=s();if(void 0===o)return void m();f(),d();const i=c();if(void 0===i)return void q();Object.prototype.hasOwnProperty.call(e,o)&&!v(i,e[o])&&Q(o,t+1),e[o]=i}return t.charCodeAt(n)!==N&&function(){throw new SyntaxError(`Quoted object key or end of object '}' expected ${H()}`)}(),n++,e}}function u(){if(t.charCodeAt(n)===S){n++,f();const e=[];let r=!0;for(;n<t.length&&t.charCodeAt(n)!==x;){r?r=!1:l();const t=c();h(t),e.push(t)}return t.charCodeAt(n)!==x&&function(){throw new SyntaxError(`Array item or end of array ']' expected ${H()}`)}(),n++,e}}function c(){f();const e=s()??function(){const e=n;t.charCodeAt(n)===F&&(n++,p(e));if(t.charCodeAt(n)===J)n++;else if(o=t.charCodeAt(n),o>=L&&o<=B)for(n++;g(t.charCodeAt(n));)n++;var o;if(t.charCodeAt(n)===T)for(n++,p(e);g(t.charCodeAt(n));)n++;if(t.charCodeAt(n)===W||t.charCodeAt(n)===P)for(n++,t.charCodeAt(n)!==F&&t.charCodeAt(n)!==_||n++,p(e);g(t.charCodeAt(n));)n++;if(n>e)return r(t.slice(e,n))}()??i()??u()??a("true",!0)??a("false",!1)??a("null",null);return f(),e}function a(e,r){if(t.slice(n,n+e.length)===e)return n+=e.length,r}function f(){for(;(e=t.charCodeAt(n))===E||e===O||e===I||e===j;)n++;var e}function s(){if(t.charCodeAt(n)===k){n++;let r="";for(;n<t.length&&t.charCodeAt(n)!==k;){if(t.charCodeAt(n)===$){const e=t[n+1],o=A[e];void 0!==o?(r+=o,n++):"u"===e?w(t.charCodeAt(n+2))&&w(t.charCodeAt(n+3))&&w(t.charCodeAt(n+4))&&w(t.charCodeAt(n+5))?(r+=String.fromCharCode(Number.parseInt(t.slice(n+2,n+6),16)),n+=5):z(n):Z(n)}else(e=t.charCodeAt(n))>=32&&e<=1114111?r+=t[n]:U(t[n]);n++}return function(){if(t.charCodeAt(n)!==k)throw new SyntaxError(`End of string '"' expected ${H()}`)}(),n++,r}var e}function l(){if(t.charCodeAt(n)!==D)throw new SyntaxError(`Comma ',' expected after value ${H()}`);n++}function d(){if(t.charCodeAt(n)!==R)throw new SyntaxError(`Colon ':' expected after property name ${H()}`);n++}function h(t){if(void 0===t)throw new SyntaxError(`Array item expected ${H()}`)}function p(e){if(!g(t.charCodeAt(n))){const r=t.slice(e,n);throw new SyntaxError(`Invalid number '${r}', expecting a digit ${H()}`)}}function m(){throw new SyntaxError(`Quoted object key expected ${H()}`)}function Q(t,e){throw new SyntaxError(`Duplicate key '${t}' encountered at position ${e}`)}function U(t){throw new SyntaxError(`Invalid character '${t}' ${G()}`)}function Z(e){const r=t.slice(e,e+2);throw new SyntaxError(`Invalid escape character '${r}' ${G()}`)}function q(){throw new SyntaxError(`Object value expected after ':' ${G()}`)}function z(e){const r=t.slice(e,e+6);throw new SyntaxError(`Invalid unicode character '${r}' ${G()}`)}function G(){return`at position ${n}`}function H(){return`${n<t.length?`but got '${t[n]}'`:"but reached end of input"} ${G()}`}},t.parseLosslessNumber=y,t.parseNumberAndBigInt=function(t){return e(t)?BigInt(t):Number.parseFloat(t)},t.reviveDate=function(t,e){return"string"==typeof e&&z.test(e)?new Date(e):e},t.stringify=function t(e,r,o,i){const u=function(t){if("number"==typeof t)return" ".repeat(t);if("string"==typeof t&&""!==t)return t;return}(o);return c("function"==typeof r?r.call({"":e},"",e):e,"");function c(e,f){if(Array.isArray(i)){const t=i.find((t=>t.test(e)));if(t){const r=t.stringify(e);if("string"!=typeof r||!n(r))throw new Error(`Invalid JSON number: output of a number stringifier must be a string containing a JSON number (output: ${r})`);return r}}return"boolean"==typeof e||"number"==typeof e||"string"==typeof e||null===e||e instanceof Date||e instanceof Boolean||e instanceof Number||e instanceof String?JSON.stringify(e):e?.isLosslessNumber||"bigint"==typeof e?e.toString():Array.isArray(e)?function(t,e){if(0===t.length)return"[]";const n=u?e+u:void 0;let o=u?"[\n":"[";for(let e=0;e<t.length;e++){const i="function"==typeof r?r.call(t,String(e),t[e]):t[e];u&&(o+=n),o+=void 0!==i&&"function"!=typeof i?c(i,n):"null",e<t.length-1&&(o+=u?",\n":",")}return o+=u?`\n${e}]`:"]",o}(e,f):e&&"object"==typeof e?function(e,n){if("function"==typeof e.toJSON)return t(e.toJSON(),r,o,void 0);const i=Array.isArray(r)?r.map(String):Object.keys(e);if(0===i.length)return"{}";const f=u?n+u:void 0;let s=!0,l=u?"{\n":"{";for(const t of i){const n="function"==typeof r?r.call(e,t,e[t]):e[t];if(a(t,n)){s?s=!1:l+=u?",\n":",";const e=JSON.stringify(t);l+=u?`${f+e}: `:`${e}:`,l+=c(n,f)}}return l+=u?`\n${n}}`:"}",l}(e,f):void 0}function a(t,e){return void 0!==e&&"function"!=typeof e&&"symbol"!=typeof e}},t.toLosslessNumber=function(t){if(a(String(t)).length>15)throw new Error(`Invalid number: contains more than 15 digits and is most likely truncated and unsafe by itself (value: ${t})`);if(Number.isNaN(t))throw new Error("Invalid number: NaN");if(!Number.isFinite(t))throw new Error(`Invalid number: ${t}`);return new h(String(t))},t.toSafeNumberOrThrow=function(t,e){const r=Number.parseFloat(t),n=c(t);if(!0===e?.approx?n&&n!==u.truncate_float:n){const e=n?.replace(/_\w+$/,"");throw new Error(`Cannot safely convert to number: the value '${t}' would ${e} and become ${r}`)}return r}}));//# sourceMappingURL=lossless-json.js.map
{
"name": "lossless-json",
"version": "4.0.1",
"version": "4.0.2",
"description": "Parse JSON without risk of losing numeric information",

@@ -24,4 +24,4 @@ "main": "lib/umd/lossless-json.js",

"test-ci": "vitest run src",
"lint": "prettier --check . && eslint src/**/*.ts test-lib/**/*.mjs tools/**/*.mjs",
"format": "prettier --write . && npm run lint -- --fix",
"lint": "biome check ./src",
"format": "biome check --write ./src",
"build": "npm-run-all build:**",

@@ -43,3 +43,3 @@ "build:clean": "del-cli lib",

"benchmark": "npm run build:esm && node tools/benchmark/run.mjs",
"prepare": "husky install"
"prepare": "husky"
},

@@ -61,14 +61,13 @@ "keywords": [

"devDependencies": {
"@babel/cli": "7.23.4",
"@babel/core": "7.23.6",
"@babel/plugin-transform-typescript": "7.23.6",
"@babel/preset-env": "7.23.6",
"@babel/preset-typescript": "7.23.3",
"@commitlint/cli": "18.4.3",
"@commitlint/config-conventional": "18.4.3",
"@babel/cli": "7.25.6",
"@babel/core": "7.25.2",
"@babel/plugin-transform-typescript": "7.25.2",
"@babel/preset-env": "7.25.4",
"@babel/preset-typescript": "7.24.7",
"@biomejs/biome": "1.9.1",
"@commitlint/cli": "19.5.0",
"@commitlint/config-conventional": "19.5.0",
"@rollup/plugin-terser": "0.4.4",
"@types/benchmark": "2.1.5",
"@types/node": "20.10.4",
"@typescript-eslint/eslint-plugin": "6.14.0",
"@typescript-eslint/parser": "6.14.0",
"@types/node": "22.5.5",
"benchmark": "2.1.4",

@@ -78,15 +77,9 @@ "cpy-cli": "5.0.0",

"del-cli": "5.1.0",
"eslint": "8.55.0",
"eslint-config-standard": "17.1.0",
"eslint-plugin-import": "2.29.0",
"eslint-plugin-n": "16.4.0",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "6.1.1",
"husky": "8.0.3",
"globals": "15.9.0",
"husky": "9.1.6",
"npm-run-all": "4.1.5",
"prettier": "3.1.1",
"rollup": "4.9.0",
"rollup": "4.21.3",
"standard-version": "9.5.0",
"typescript": "5.3.3",
"vitest": "1.0.4"
"typescript": "5.6.2",
"vitest": "2.1.1"
},

@@ -93,0 +86,0 @@ "files": [

@@ -348,2 +348,3 @@ # lossless-json

- https://github.com/jawj/json-custom-numbers
- https://github.com/sidorares/json-bigint

@@ -350,0 +351,0 @@ - https://github.com/nicolasparada/js-json-bigint

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc