UNPKG

lossless-json

Version:

Parse JSON without risk of losing numeric information

2 lines (1 loc) 9.45 kB
!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 n.test(t)}const n=/^-?[0-9]+$/;function r(t){return o.test(t)}const o=/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/;function i(t,n){const r=Number.parseFloat(t),o=String(r);if(t===o)return!0;const i=f(t),u=f(o);if(i===u)return!0;if(!0===n?.approx){const n=14;if(!e(t)&&u.length>=n&&i.startsWith(u.substring(0,n)))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 n=Number.parseFloat(t);return Number.isFinite(n)?0===n?u.underflow:u.truncate_float:u.overflow}function s(t){const e=t.match(/^(-?)(\d+\.?\d*)([eE]([+-]?\d+))?$/);if(!e)throw new SyntaxError(`Invalid number: ${t}`);const n=e[1],r=e[2];let o=void 0!==e[4]?Number.parseInt(e[4]):0;const i=r.indexOf(".");o+=-1!==i?i-1:r.length-1;const u=r.replace(".","").replace(/^0*/,(t=>(o-=t.length,""))).replace(/0*$/,"");return u.length>0?{sign:n,digits:u,exponent:o}:{sign:n,digits:"0",exponent:o+1}}function a(t,e){if(t===e)return 0;const n=s(t),r=s(e),o="-"===n.sign?-1:1;return n.sign!==r.sign?"0"===n.digits&&"0"===r.digits?0:o:n.exponent!==r.exponent?n.exponent>r.exponent?o:n.exponent<r.exponent?-o:0:n.digits>r.digits?o:n.digits<r.digits?-o:0}function f(t){const{start:e,end:n}=l(t),r=t.substring(e,n),o=r.indexOf(".");return-1===o?r:r.substring(0,o)+r.substring(o+1)}function l(t){let e=0;for("-"===t[0]&&e++;"0"===t[e]||"."===t[e];)e++;let n=t.lastIndexOf("e");for(-1===n&&(n=t.lastIndexOf("E")),-1===n&&(n=t.length);("0"===t[n-1]||"."===t[n-1])&&n>e;)n--;return{start:e,end:n}}class d{isLosslessNumber=!0;constructor(t){if(!r(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 h(t){return t&&"object"==typeof t&&t.isLosslessNumber||!1}function p(t){return new d(t)}function y(t,e,n,r){return Array.isArray(n)?r.call(t,e,function(t,e){for(let n=0;n<t.length;n++)t[n]=y(t,String(n),t[n],e);return t}(n,r)):n&&"object"==typeof n&&!h(n)?r.call(t,e,function(t,e){for(const n of Object.keys(t)){const r=y(t,n,t[n],e);void 0!==r?t[n]=r:delete t[n]}return t}(n,r)):r.call(t,e,n)}function g(t){return t>=_&&t<=J||t>=R&&t<=W||t>=Q&&t<=Z}function b(t){return t>=_&&t<=J}function w(t,e){if(t===e)return!0;if(Array.isArray(t)&&Array.isArray(e))return t.length===e.length&&t.every(((t,n)=>w(t,e[n])));if(m(t)&&m(e)){return[...new Set([...Object.keys(t),...Object.keys(e)])].every((n=>w(t[n],e[n])))}return!1}function m(t){return"object"==typeof t&&null!==t}const v={'"':'"',"\\":"\\","/":"/",b:"\b",f:"\f",n:"\n",r:"\r",t:"\t"},x=92,A=123,$=125,N=91,S=93,C=32,E=10,O=9,I=13,j=34,k=43,L=45,_=48,F=49,J=57,B=44,D=46,T=58,R=65,Q=97,U=69,P=101,W=70,Z=102;const q=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;t.LosslessNumber=d,t.UnsafeNumberReason=u,t.compareLosslessNumber=function(t,e){return a(t.value,e.value)},t.compareNumber=a,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=h,t.isNumber=r,t.isSafeNumber=i,t.parse=function(t,e){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:p,r=0;const o=c();return function(t){if(void 0===t)throw new SyntaxError(`JSON value expected ${H()}`)}(o),function(){if(r<t.length)throw new SyntaxError(`Expected end of input ${H()}`)}(),e?function(t,e){return y({"":t},"",t,e)}(o,e):o;function i(){if(t.charCodeAt(r)===A){r++,a();const e={};let n=!0;for(;r<t.length&&t.charCodeAt(r)!==$;){n?n=!1:(l(),a());const t=r,o=f();if(void 0===o)return void R();a(),d();const i=c();if(void 0===i)return void q();Object.prototype.hasOwnProperty.call(e,o)&&!w(i,e[o])&&Q(o,t+1),e[o]=i}return t.charCodeAt(r)!==$&&function(){throw new SyntaxError(`Quoted object key or end of object '}' expected ${H()}`)}(),r++,e}}function u(){if(t.charCodeAt(r)===N){r++,a();const e=[];let n=!0;for(;r<t.length&&t.charCodeAt(r)!==S;){n?n=!1:l();const t=c();h(t),e.push(t)}return t.charCodeAt(r)!==S&&function(){throw new SyntaxError(`Array item or end of array ']' expected ${H()}`)}(),r++,e}}function c(){a();const e=f()??function(){const e=r;t.charCodeAt(r)===L&&(r++,m(e));if(t.charCodeAt(r)===_)r++;else if(o=t.charCodeAt(r),o>=F&&o<=J)for(r++;b(t.charCodeAt(r));)r++;var o;if(t.charCodeAt(r)===D)for(r++,m(e);b(t.charCodeAt(r));)r++;if(t.charCodeAt(r)===P||t.charCodeAt(r)===U)for(r++,t.charCodeAt(r)!==L&&t.charCodeAt(r)!==k||r++,m(e);b(t.charCodeAt(r));)r++;if(r>e)return n(t.slice(e,r))}()??i()??u()??s("true",!0)??s("false",!1)??s("null",null);return a(),e}function s(e,n){if(t.slice(r,r+e.length)===e)return r+=e.length,n}function a(){for(;(e=t.charCodeAt(r))===C||e===E||e===O||e===I;)r++;var e}function f(){if(t.charCodeAt(r)===j){r++;let n="";for(;r<t.length&&t.charCodeAt(r)!==j;){if(t.charCodeAt(r)===x){const e=t[r+1],o=v[e];void 0!==o?(n+=o,r++):"u"===e?g(t.charCodeAt(r+2))&&g(t.charCodeAt(r+3))&&g(t.charCodeAt(r+4))&&g(t.charCodeAt(r+5))?(n+=String.fromCharCode(Number.parseInt(t.slice(r+2,r+6),16)),r+=5):z(r):Z(r)}else(e=t.charCodeAt(r))>=32&&e<=1114111?n+=t[r]:W(t[r]);r++}return function(){if(t.charCodeAt(r)!==j)throw new SyntaxError(`End of string '"' expected ${H()}`)}(),r++,n}var e}function l(){if(t.charCodeAt(r)!==B)throw new SyntaxError(`Comma ',' expected after value ${H()}`);r++}function d(){if(t.charCodeAt(r)!==T)throw new SyntaxError(`Colon ':' expected after property name ${H()}`);r++}function h(t){if(void 0===t)throw new SyntaxError(`Array item expected ${H()}`)}function m(e){if(!b(t.charCodeAt(r))){const n=t.slice(e,r);throw new SyntaxError(`Invalid number '${n}', expecting a digit ${H()}`)}}function R(){throw new SyntaxError(`Quoted object key expected ${H()}`)}function Q(t,e){throw new SyntaxError(`Duplicate key '${t}' encountered at position ${e}`)}function W(t){throw new SyntaxError(`Invalid character '${t}' ${G()}`)}function Z(e){const n=t.slice(e,e+2);throw new SyntaxError(`Invalid escape character '${n}' ${G()}`)}function q(){throw new SyntaxError(`Object value expected after ':' ${G()}`)}function z(e){const n=t.slice(e,e+6);throw new SyntaxError(`Invalid unicode character '${n}' ${G()}`)}function G(){return`at position ${r}`}function H(){return`${r<t.length?`but got '${t[r]}'`:"but reached end of input"} ${G()}`}},t.parseLosslessNumber=p,t.parseNumberAndBigInt=function(t){return e(t)?BigInt(t):Number.parseFloat(t)},t.reviveDate=function(t,e){return"string"==typeof e&&q.test(e)?new Date(e):e},t.splitNumber=s,t.stringify=function t(e,n,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 n?n.call({"":e},"",e):e,"");function c(e,a){if(Array.isArray(i)){const t=i.find((t=>t.test(e)));if(t){const n=t.stringify(e);if("string"!=typeof n||!r(n))throw new Error(`Invalid JSON number: output of a number stringifier must be a string containing a JSON number (output: ${n})`);return n}}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 r=u?e+u:void 0;let o=u?"[\n":"[";for(let e=0;e<t.length;e++){const i="function"==typeof n?n.call(t,String(e),t[e]):t[e];u&&(o+=r),o+=void 0!==i&&"function"!=typeof i?c(i,r):"null",e<t.length-1&&(o+=u?",\n":",")}return o+=u?`\n${e}]`:"]",o}(e,a):e&&"object"==typeof e?function(e,r){if("function"==typeof e.toJSON)return t(e.toJSON(),n,o,void 0);const i=Array.isArray(n)?n.map(String):Object.keys(e);if(0===i.length)return"{}";const a=u?r+u:void 0;let f=!0,l=u?"{\n":"{";for(const t of i){const r="function"==typeof n?n.call(e,t,e[t]):e[t];if(s(t,r)){f?f=!1:l+=u?",\n":",";const e=JSON.stringify(t);l+=u?`${a+e}: `:`${e}:`,l+=c(r,a)}}return l+=u?`\n${r}}`:"}",l}(e,a):void 0}function s(t,e){return void 0!==e&&"function"!=typeof e&&"symbol"!=typeof e}},t.toLosslessNumber=function(t){if(function(t){const{start:e,end:n}=l(t),r=t.indexOf(".");return-1===r||r<e||r>n?n-e:n-e-1}(String(t))>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 d(String(t))},t.toSafeNumberOrThrow=function(t,e){const n=Number.parseFloat(t),r=c(t);if(!0===e?.approx?r&&r!==u.truncate_float:r){const e=r?.replace(/_\w+$/,"");throw new Error(`Cannot safely convert to number: the value '${t}' would ${e} and become ${n}`)}return n}}));//# sourceMappingURL=lossless-json.js.map