@discoveryjs/json-ext
Advanced tools
Comparing version 0.6.0 to 0.6.1
@@ -352,8 +352,12 @@ (function (global, factory) { | ||
space = normalizeSpace(optionsOrReplacer.space); | ||
const keyStrings = /* @__PURE__ */ new Map(); | ||
const visited = []; | ||
const rootValue = { "": value }; | ||
let prevState = null; | ||
let state = () => printEntry("", value); | ||
let stateValue = rootValue; | ||
let stateEmpty = true; | ||
let stateKeys = [""]; | ||
let stateIndex = 0; | ||
let buffer = ""; | ||
let depth = 0; | ||
let stack = null; | ||
let first = false; | ||
let visited = /* @__PURE__ */ new WeakSet(); | ||
let processing = false; | ||
let getKeys = Object.keys; | ||
@@ -365,115 +369,90 @@ if (Array.isArray(replacer)) { | ||
} | ||
pushStack(processRoot, value, null); | ||
while (stack !== null) { | ||
processing = true; | ||
while (stack !== null && !stack.awaiting) { | ||
stack.handler(); | ||
if (!processing) { | ||
while (true) { | ||
state(); | ||
if (buffer.length >= highWaterMark || prevState === null) { | ||
yield buffer; | ||
buffer = ""; | ||
if (prevState === null) { | ||
break; | ||
} | ||
} | ||
processing = false; | ||
yield buffer; | ||
buffer = ""; | ||
} | ||
function processRoot() { | ||
const { value: value2 } = stack; | ||
popStack(); | ||
processValue({ "": value2 }, "", value2, () => { | ||
}); | ||
} | ||
function processObjectEntry(key) { | ||
if (first === false) { | ||
first = true; | ||
} else { | ||
push(","); | ||
function printObject() { | ||
if (stateIndex === 0) { | ||
stateKeys = getKeys(stateValue); | ||
buffer += "{"; | ||
} | ||
if (space) { | ||
push(` | ||
${space.repeat(depth)}${encodeString(key)}: `); | ||
} else { | ||
push(encodeString(key) + ":"); | ||
if (stateIndex === stateKeys.length) { | ||
buffer += space && !stateEmpty ? ` | ||
${space.repeat(visited.length - 1)}}` : "}"; | ||
popState(); | ||
return; | ||
} | ||
const key = stateKeys[stateIndex++]; | ||
printEntry(key, stateValue[key]); | ||
} | ||
function processObject() { | ||
const current = stack; | ||
if (current.index === current.keys.length) { | ||
if (space && first) { | ||
push(` | ||
${space.repeat(depth - 1)}}`); | ||
} else { | ||
push("}"); | ||
} | ||
popStack(); | ||
function printArray() { | ||
if (stateIndex === 0) { | ||
buffer += "["; | ||
} | ||
if (stateIndex === stateValue.length) { | ||
buffer += space && !stateEmpty ? ` | ||
${space.repeat(visited.length - 1)}]` : "]"; | ||
popState(); | ||
return; | ||
} | ||
const key = current.keys[current.index]; | ||
processValue(current.value, key, current.value[key], processObjectEntry); | ||
current.index++; | ||
printEntry(stateIndex, stateValue[stateIndex++]); | ||
} | ||
function processArrayItem(index) { | ||
if (index !== 0) { | ||
push(","); | ||
function printEntryPrelude(key) { | ||
if (stateEmpty) { | ||
stateEmpty = false; | ||
} else { | ||
buffer += ","; | ||
} | ||
if (space) { | ||
push(` | ||
${space.repeat(depth)}`); | ||
if (space && prevState !== null) { | ||
buffer += ` | ||
${space.repeat(visited.length)}`; | ||
} | ||
} | ||
function processArray() { | ||
const current = stack; | ||
if (current.index === current.value.length) { | ||
if (space && current.index !== 0) { | ||
push(` | ||
${space.repeat(depth - 1)}]`); | ||
} else { | ||
push("]"); | ||
if (state === printObject) { | ||
let keyString = keyStrings.get(key); | ||
if (keyString === void 0) { | ||
keyStrings.set(key, keyString = encodeString(key) + (space ? ": " : ":")); | ||
} | ||
popStack(); | ||
return; | ||
buffer += keyString; | ||
} | ||
processValue(current.value, current.index, current.value[current.index], processArrayItem); | ||
current.index++; | ||
} | ||
function processValue(holder, key, value2, callback) { | ||
value2 = replaceValue(holder, key, value2, replacer); | ||
function printEntry(key, value2) { | ||
value2 = replaceValue(stateValue, key, value2, replacer); | ||
if (value2 === null || typeof value2 !== "object") { | ||
if (callback !== processObjectEntry || value2 !== void 0) { | ||
callback(key); | ||
if (state !== printObject || value2 !== void 0) { | ||
printEntryPrelude(key); | ||
pushPrimitive(value2); | ||
} | ||
} else if (Array.isArray(value2)) { | ||
callback(key); | ||
circularCheck(value2); | ||
depth++; | ||
push("["); | ||
pushStack(processArray, value2, null); | ||
} else { | ||
callback(key); | ||
circularCheck(value2); | ||
depth++; | ||
push("{"); | ||
pushStack(processObject, value2, getKeys(value2)); | ||
if (visited.includes(value2)) { | ||
throw new TypeError("Converting circular structure to JSON"); | ||
} | ||
printEntryPrelude(key); | ||
visited.push(value2); | ||
pushState(); | ||
state = Array.isArray(value2) ? printArray : printObject; | ||
stateValue = value2; | ||
stateEmpty = true; | ||
stateIndex = 0; | ||
} | ||
} | ||
function circularCheck(value2) { | ||
if (visited.has(value2)) { | ||
throw new TypeError("Converting circular structure to JSON"); | ||
} | ||
visited.add(value2); | ||
} | ||
function pushPrimitive(value2) { | ||
switch (typeof value2) { | ||
case "string": | ||
push(encodeString(value2)); | ||
buffer += encodeString(value2); | ||
break; | ||
case "number": | ||
push(Number.isFinite(value2) ? value2 : "null"); | ||
buffer += Number.isFinite(value2) ? String(value2) : "null"; | ||
break; | ||
case "boolean": | ||
push(value2 ? "true" : "false"); | ||
buffer += value2 ? "true" : "false"; | ||
break; | ||
case "undefined": | ||
case "object": | ||
push("null"); | ||
buffer += "null"; | ||
break; | ||
@@ -484,25 +463,19 @@ default: | ||
} | ||
function pushStack(handler, value2, keys) { | ||
first = false; | ||
return stack = { | ||
handler, | ||
value: value2, | ||
index: 0, | ||
keys, | ||
prev: stack | ||
function pushState() { | ||
prevState = { | ||
keys: stateKeys, | ||
index: stateIndex, | ||
prev: prevState | ||
}; | ||
} | ||
function popStack() { | ||
const { handler, value: value2 } = stack; | ||
if (handler === processObject || handler === processArray) { | ||
visited.delete(value2); | ||
depth--; | ||
} | ||
stack = stack.prev; | ||
first = true; | ||
function popState() { | ||
visited.pop(); | ||
const value2 = visited.length > 0 ? visited[visited.length - 1] : rootValue; | ||
state = Array.isArray(value2) ? printArray : printObject; | ||
stateValue = value2; | ||
stateEmpty = false; | ||
stateKeys = prevState.keys; | ||
stateIndex = prevState.index; | ||
prevState = prevState.prev; | ||
} | ||
function push(data) { | ||
buffer += data; | ||
processing = buffer.length < highWaterMark; | ||
} | ||
} | ||
@@ -522,3 +495,3 @@ | ||
}; | ||
var charLength2048 = Array.from({ length: 2048 }).map((_, code) => { | ||
var charLength2048 = Uint8Array.from({ length: 2048 }, (_, code) => { | ||
if (hasOwn(escapableCharCodeSubstitution, code)) { | ||
@@ -539,2 +512,5 @@ return 2; | ||
function stringLength(str) { | ||
if (!/[^\x20\x21\x23-\x5B\x5D-\x7F]/.test(str)) { | ||
return str.length + 2; | ||
} | ||
let len = 0; | ||
@@ -559,2 +535,20 @@ let prevLeadingSurrogate = false; | ||
} | ||
function intLength(num) { | ||
let len = 0; | ||
if (num < 0) { | ||
len = 1; | ||
num = -num; | ||
} | ||
if (num >= 1e9) { | ||
len += 9; | ||
num = (num - num % 1e9) / 1e9; | ||
} | ||
if (num >= 1e4) { | ||
if (num >= 1e6) { | ||
return len + (num >= 1e8 ? 9 : num >= 1e7 ? 8 : 7); | ||
} | ||
return len + (num >= 1e5 ? 6 : 5); | ||
} | ||
return len + (num >= 100 ? num >= 1e3 ? 4 : 3 : num >= 10 ? 2 : 1); | ||
} | ||
function primitiveLength(value) { | ||
@@ -565,3 +559,3 @@ switch (typeof value) { | ||
case "number": | ||
return Number.isFinite(value) ? String(value).length : 4; | ||
return Number.isFinite(value) ? Number.isInteger(value) ? intLength(value) : String(value).length : 4; | ||
case "boolean": | ||
@@ -587,12 +581,14 @@ return value ? 4 : 5; | ||
} | ||
let allowlist = null; | ||
const continueOnCircular = Boolean(optionsOrReplacer.continueOnCircular); | ||
let replacer = normalizeReplacer(optionsOrReplacer.replacer); | ||
const continueOnCircular = Boolean(optionsOrReplacer.continueOnCircular); | ||
let getKeys = Object.keys; | ||
if (Array.isArray(replacer)) { | ||
allowlist = new Set(replacer); | ||
const allowlist = replacer; | ||
getKeys = () => allowlist; | ||
replacer = null; | ||
} | ||
space = spaceLength(space); | ||
const visited = /* @__PURE__ */ new WeakMap(); | ||
const stack = /* @__PURE__ */ new Set(); | ||
const keysLength = /* @__PURE__ */ new Map(); | ||
const visited = /* @__PURE__ */ new Map(); | ||
const stack = []; | ||
const circular = /* @__PURE__ */ new Set(); | ||
@@ -602,3 +598,7 @@ const root = { "": value }; | ||
let bytes = 0; | ||
let objects = 0; | ||
walk(root, "", value); | ||
if (bytes === 0) { | ||
bytes += 9; | ||
} | ||
return { | ||
@@ -616,7 +616,5 @@ bytes: isNaN(bytes) ? Infinity : bytes, | ||
bytes += primitiveLength(value2); | ||
} else if (holder === root) { | ||
bytes += 9; | ||
} | ||
} else { | ||
if (stack.has(value2)) { | ||
if (stack.includes(value2)) { | ||
circular.add(value2); | ||
@@ -633,43 +631,36 @@ bytes += 4; | ||
} | ||
objects++; | ||
const prevObjects = objects; | ||
const valueBytes = bytes; | ||
let valueLength = 0; | ||
stack.push(value2); | ||
if (Array.isArray(value2)) { | ||
const valueLength = bytes; | ||
bytes += 2; | ||
stack.add(value2); | ||
for (let i = 0; i < value2.length; i++) { | ||
valueLength = value2.length; | ||
for (let i = 0; i < valueLength; i++) { | ||
walk(value2, i, value2[i]); | ||
} | ||
if (value2.length > 1) { | ||
bytes += value2.length - 1; | ||
} | ||
stack.delete(value2); | ||
if (space > 0 && value2.length > 0) { | ||
bytes += (1 + (stack.size + 1) * space) * value2.length; | ||
bytes += 1 + stack.size * space; | ||
} | ||
visited.set(value2, bytes - valueLength); | ||
} else { | ||
const valueLength = bytes; | ||
let entries = 0; | ||
bytes += 2; | ||
stack.add(value2); | ||
for (const key2 in value2) { | ||
if (hasOwn(value2, key2) && (allowlist === null || allowlist.has(key2))) { | ||
const prevLength = bytes; | ||
walk(value2, key2, value2[key2]); | ||
if (prevLength !== bytes) { | ||
bytes += stringLength(key2) + 1; | ||
entries++; | ||
let prevLength = bytes; | ||
for (const key2 of getKeys(value2)) { | ||
walk(value2, key2, value2[key2]); | ||
if (prevLength !== bytes) { | ||
let keyLen = keysLength.get(key2); | ||
if (keyLen === void 0) { | ||
keysLength.set(key2, keyLen = stringLength(key2) + (space > 0 ? 2 : 1)); | ||
} | ||
bytes += keyLen; | ||
valueLength++; | ||
prevLength = bytes; | ||
} | ||
} | ||
if (entries > 1) { | ||
bytes += entries - 1; | ||
} | ||
stack.delete(value2); | ||
if (space > 0 && entries > 0) { | ||
bytes += (1 + (stack.size + 1) * space + 1) * entries; | ||
bytes += 1 + stack.size * space; | ||
} | ||
visited.set(value2, bytes - valueLength); | ||
} | ||
bytes += valueLength === 0 ? 2 : 1 + valueLength; | ||
if (space > 0 && valueLength > 0) { | ||
bytes += (1 + stack.length * space) * valueLength + // for each key-value: \n{space} | ||
1 + (stack.length - 1) * space; | ||
} | ||
stack.pop(); | ||
if (prevObjects !== objects) { | ||
visited.set(value2, bytes - valueBytes); | ||
} | ||
} | ||
@@ -683,8 +674,12 @@ } | ||
const reader = stream.getReader(); | ||
while (true) { | ||
const { value, done } = await reader.read(); | ||
if (done) { | ||
break; | ||
try { | ||
while (true) { | ||
const { value, done } = await reader.read(); | ||
if (done) { | ||
break; | ||
} | ||
yield value; | ||
} | ||
yield value; | ||
} finally { | ||
reader.releaseLock(); | ||
} | ||
@@ -691,0 +686,0 @@ }); |
@@ -6,7 +6,6 @@ (function (global, factory) { | ||
}(typeof globalThis != 'undefined' ? globalThis : typeof window != 'undefined' ? window : typeof global != 'undefined' ? global : typeof self != 'undefined' ? self : this, (function () { | ||
var exports=(()=>{var L=Object.defineProperty;var M=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var K=Object.prototype.hasOwnProperty;var U=(e,t)=>{for(var n in t)L(e,n,{get:t[n],enumerable:!0})},Y=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of _(t))!K.call(e,i)&&i!==n&&L(e,i,{get:()=>t[i],enumerable:!(r=M(t,i))||r.enumerable});return e};var G=e=>Y(L({},"__esModule",{value:!0}),e);var st={};U(st,{createStringifyWebStream:()=>V,parseChunked:()=>B,parseFromWebStream:()=>$,stringifyChunked:()=>w,stringifyInfo:()=>W});function j(e){return typeof e=="object"&&e!==null&&(typeof e[Symbol.iterator]=="function"||typeof e[Symbol.asyncIterator]=="function")}function O(e,t,n,r){switch(n&&typeof n.toJSON=="function"&&(n=n.toJSON()),r!==null&&(n=r.call(e,String(t),n)),typeof n){case"function":case"symbol":n=void 0;break;case"object":if(n!==null){let i=n.constructor;(i===String||i===Number||i===Boolean)&&(n=n.valueOf())}break}return n}function F(e){return typeof e=="function"?e:Array.isArray(e)?[...new Set(e.map(n=>{let r=n&&n.constructor;return r===String||r===Number?String(n):null}).filter(n=>typeof n=="string"))]:null}function N(e){return typeof e=="number"?!Number.isFinite(e)||e<1?!1:" ".repeat(Math.min(e,10)):typeof e=="string"&&e.slice(0,10)||!1}var k=1,H=2,Q=new TextDecoder;function X(e,t){return e.name==="SyntaxError"&&t.jsonParseOffset&&(e.message=e.message.replace(/at position (\d+)/,(n,r)=>"at position "+(Number(r)+t.jsonParseOffset))),e}function Z(e,t){let n=e.length;e.length+=t.length;for(let r=0;r<t.length;r++)e[n+r]=t[r]}async function B(e){let t=typeof e=="function"?e():e;if(j(t)){let n=new z;try{for await(let r of t){if(typeof r!="string"&&!ArrayBuffer.isView(r))throw new TypeError("Invalid chunk: Expected string, TypedArray or Buffer");n.push(r)}return n.finish()}catch(r){throw X(r,n)}}throw new TypeError("Invalid chunk emitter: Expected an Iterable, AsyncIterable, generator, async generator, or a function returning an Iterable or AsyncIterable")}var z=class{constructor(){this.value=void 0,this.valueStack=null,this.stack=new Array(100),this.lastFlushDepth=0,this.flushDepth=0,this.stateString=!1,this.stateStringEscape=!1,this.pendingByteSeq=null,this.pendingChunk=null,this.chunkOffset=0,this.jsonParseOffset=0}parseAndAppend(t,n){this.stack[this.lastFlushDepth-1]===k?(n&&(this.jsonParseOffset--,t="{"+t+"}"),Object.assign(this.valueStack.value,JSON.parse(t))):(n&&(this.jsonParseOffset--,t="["+t+"]"),Z(this.valueStack.value,JSON.parse(t)))}prepareAddition(t){let{value:n}=this.valueStack;if(Array.isArray(n)?n.length!==0:Object.keys(n).length!==0){if(t[0]===",")return this.jsonParseOffset++,t.slice(1);if(t[0]!=="}"&&t[0]!=="]")return this.jsonParseOffset-=3,"[[]"+t}return t}flush(t,n,r){let i=t.slice(n,r);if(this.jsonParseOffset=this.chunkOffset+n,this.pendingChunk!==null&&(i=this.pendingChunk+i,this.jsonParseOffset-=this.pendingChunk.length,this.pendingChunk=null),this.flushDepth===this.lastFlushDepth)this.flushDepth>0?this.parseAndAppend(this.prepareAddition(i),!0):(this.value=JSON.parse(i),this.valueStack={value:this.value,prev:null});else if(this.flushDepth>this.lastFlushDepth){for(let s=this.flushDepth-1;s>=this.lastFlushDepth;s--)i+=this.stack[s]===k?"}":"]";this.lastFlushDepth===0?(this.value=JSON.parse(i),this.valueStack={value:this.value,prev:null}):this.parseAndAppend(this.prepareAddition(i),!0);for(let s=this.lastFlushDepth||1;s<this.flushDepth;s++){let o=this.valueStack.value;if(this.stack[s-1]===k){let h;for(h in o);o=o[h]}else o=o[o.length-1];this.valueStack={value:o,prev:this.valueStack}}}else{i=this.prepareAddition(i);for(let s=this.lastFlushDepth-1;s>=this.flushDepth;s--)this.jsonParseOffset--,i=(this.stack[s]===k?"{":"[")+i;this.parseAndAppend(i,!1);for(let s=this.lastFlushDepth-1;s>=this.flushDepth;s--)this.valueStack=this.valueStack.prev}this.lastFlushDepth=this.flushDepth}push(t){if(typeof t!="string"){if(this.pendingByteSeq!==null){let s=t;t=new Uint8Array(this.pendingByteSeq.length+s.length),t.set(this.pendingByteSeq),t.set(s,this.pendingByteSeq.length),this.pendingByteSeq=null}if(t[t.length-1]>127)for(let s=0;s<t.length;s++){let o=t[t.length-1-s];if(o>>6===3){s++,(s!==4&&o>>3===30||s!==3&&o>>4===14||s!==2&&o>>5===6)&&(this.pendingByteSeq=t.slice(t.length-s),t=t.slice(0,-s));break}}t=Q.decode(t)}let n=t.length,r=0,i=0;t:for(let s=0;s<n;s++){if(this.stateString){for(;s<n;s++)if(this.stateStringEscape)this.stateStringEscape=!1;else switch(t.charCodeAt(s)){case 34:this.stateString=!1;continue t;case 92:this.stateStringEscape=!0}break}switch(t.charCodeAt(s)){case 34:this.stateString=!0,this.stateStringEscape=!1;break;case 44:i=s;break;case 123:i=s+1,this.stack[this.flushDepth++]=k;break;case 91:i=s+1,this.stack[this.flushDepth++]=H;break;case 93:case 125:i=s+1,this.flushDepth--,this.flushDepth<this.lastFlushDepth&&(this.flush(t,r,i),r=i);break;case 9:case 10:case 13:case 32:r===s&&r++,i===s&&i++;break}}i>r&&this.flush(t,r,i),i<n&&(this.pendingChunk!==null?this.pendingChunk+=t:this.pendingChunk=t.slice(i,n)),this.chunkOffset+=n}finish(){return this.pendingChunk!==null&&(this.flush("",0,0),this.pendingChunk=null),this.value}};function T(e){return/[^\x20\x21\x23-\x5B\x5D-\uD799]/.test(e)?JSON.stringify(e):'"'+e+'"'}function*w(e,t,n){(t===null||Array.isArray(t)||typeof t!="object")&&(t={replacer:t,space:n});let r=Number(t.highWaterMark)||16384,i=F(t.replacer);n=N(t.space);let s="",o=0,h=null,g=!1,S=new WeakSet,b=!1,a=Object.keys;if(Array.isArray(i)){let f=i;a=()=>f,i=null}for(P(m,e,null);h!==null;){for(b=!0;h!==null&&!h.awaiting&&(h.handler(),!!b););b=!1,yield s,s=""}function m(){let{value:f}=h;E(),c({"":f},"",f,()=>{})}function x(f){g===!1?g=!0:u(","),u(n?` | ||
${n.repeat(o)}${T(f)}: `:T(f)+":")}function D(){let f=h;if(f.index===f.keys.length){u(n&&g?` | ||
${n.repeat(o-1)}}`:"}"),E();return}let d=f.keys[f.index];c(f.value,d,f.value[d],x),f.index++}function l(f){f!==0&&u(","),n&&u(` | ||
${n.repeat(o)}`)}function A(){let f=h;if(f.index===f.value.length){n&&f.index!==0?u(` | ||
${n.repeat(o-1)}]`):u("]"),E();return}c(f.value,f.index,f.value[f.index],l),f.index++}function c(f,d,p,C){p=O(f,d,p,i),p===null||typeof p!="object"?(C!==x||p!==void 0)&&(C(d),I(p)):Array.isArray(p)?(C(d),y(p),o++,u("["),P(A,p,null)):(C(d),y(p),o++,u("{"),P(D,p,a(p)))}function y(f){if(S.has(f))throw new TypeError("Converting circular structure to JSON");S.add(f)}function I(f){switch(typeof f){case"string":u(T(f));break;case"number":u(Number.isFinite(f)?f:"null");break;case"boolean":u(f?"true":"false");break;case"undefined":case"object":u("null");break;default:throw new TypeError(`Do not know how to serialize a ${f.constructor?.name||typeof f}`)}}function P(f,d,p){return g=!1,h={handler:f,value:d,index:0,keys:p,prev:h}}function E(){let{handler:f,value:d}=h;(f===D||f===A)&&(S.delete(d),o--),h=h.prev,g=!0}function u(f){s+=f,b=s.length<r}}var q=typeof Object.hasOwn=="function"?Object.hasOwn:(e,t)=>Object.hasOwnProperty.call(e,t),R={8:"\\b",9:"\\t",10:"\\n",12:"\\f",13:"\\r",34:'\\"',92:"\\\\"},v=Array.from({length:2048}).map((e,t)=>q(R,t)?2:t<32?6:t<128?1:2);function tt(e){return e>=55296&&e<=56319}function et(e){return e>=56320&&e<=57343}function J(e){let t=0,n=!1;for(let r=0;r<e.length;r++){let i=e.charCodeAt(r);if(i<2048)t+=v[i];else if(tt(i)){t+=6,n=!0;continue}else et(i)?t=n?t-2:t+6:t+=3;n=!1}return t+2}function nt(e){switch(typeof e){case"string":return J(e);case"number":return Number.isFinite(e)?String(e).length:4;case"boolean":return e?4:5;case"undefined":case"object":return 4;default:return 0}}function it(e){return e=N(e),typeof e=="string"?e.length:0}function W(e,t,n){(t===null||Array.isArray(t)||typeof t!="object")&&(t={replacer:t,space:n});let r=null,i=F(t.replacer),s=!!t.continueOnCircular;Array.isArray(i)&&(r=new Set(i),i=null),n=it(n);let o=new WeakMap,h=new Set,g=new Set,S={"":e},b=!1,a=0;return m(S,"",e),{bytes:isNaN(a)?1/0:a,circular:[...g]};function m(x,D,l){if(!b)if(l=O(x,D,l,i),l===null||typeof l!="object")l!==void 0||Array.isArray(x)?a+=nt(l):x===S&&(a+=9);else{if(h.has(l)){g.add(l),a+=4,s||(b=!0);return}if(o.has(l)){a+=o.get(l);return}if(Array.isArray(l)){let A=a;a+=2,h.add(l);for(let c=0;c<l.length;c++)m(l,c,l[c]);l.length>1&&(a+=l.length-1),h.delete(l),n>0&&l.length>0&&(a+=(1+(h.size+1)*n)*l.length,a+=1+h.size*n),o.set(l,a-A)}else{let A=a,c=0;a+=2,h.add(l);for(let y in l)if(q(l,y)&&(r===null||r.has(y))){let I=a;m(l,y,l[y]),I!==a&&(a+=J(y)+1,c++)}c>1&&(a+=c-1),h.delete(l),n>0&&c>0&&(a+=(1+(h.size+1)*n+1)*c,a+=1+h.size*n),o.set(l,a-A)}}}}function $(e){return B(j(e)?e:async function*(){let t=e.getReader();for(;;){let{value:n,done:r}=await t.read();if(r)break;yield n}})}function V(e,t,n){return typeof ReadableStream.from=="function"?ReadableStream.from(w(e,t,n)):new ReadableStream({start(){this.generator=w(e,t,n)},pull(r){let{value:i,done:s}=this.generator.next();s?r.close():r.enqueue(i)},cancel(){this.generator=null}})}return G(st);})(); | ||
var exports=(()=>{var L=Object.defineProperty;var M=Object.getOwnPropertyDescriptor;var V=Object.getOwnPropertyNames;var W=Object.prototype.hasOwnProperty;var K=(e,t)=>{for(var n in t)L(e,n,{get:t[n],enumerable:!0})},_=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of V(t))!W.call(e,i)&&i!==n&&L(e,i,{get:()=>t[i],enumerable:!(r=M(t,i))||r.enumerable});return e};var $=e=>_(L({},"__esModule",{value:!0}),e);var it={};K(it,{createStringifyWebStream:()=>z,parseChunked:()=>I,parseFromWebStream:()=>J,stringifyChunked:()=>m,stringifyInfo:()=>q});function O(e){return typeof e=="object"&&e!==null&&(typeof e[Symbol.iterator]=="function"||typeof e[Symbol.asyncIterator]=="function")}function F(e,t,n,r){switch(n&&typeof n.toJSON=="function"&&(n=n.toJSON()),r!==null&&(n=r.call(e,String(t),n)),typeof n){case"function":case"symbol":n=void 0;break;case"object":if(n!==null){let i=n.constructor;(i===String||i===Number||i===Boolean)&&(n=n.valueOf())}break}return n}function B(e){return typeof e=="function"?e:Array.isArray(e)?[...new Set(e.map(n=>{let r=n&&n.constructor;return r===String||r===Number?String(n):null}).filter(n=>typeof n=="string"))]:null}function N(e){return typeof e=="number"?!Number.isFinite(e)||e<1?!1:" ".repeat(Math.min(e,10)):typeof e=="string"&&e.slice(0,10)||!1}var C=1,U=2,Y=new TextDecoder;function G(e,t){return e.name==="SyntaxError"&&t.jsonParseOffset&&(e.message=e.message.replace(/at position (\d+)/,(n,r)=>"at position "+(Number(r)+t.jsonParseOffset))),e}function H(e,t){let n=e.length;e.length+=t.length;for(let r=0;r<t.length;r++)e[n+r]=t[r]}async function I(e){let t=typeof e=="function"?e():e;if(O(t)){let n=new P;try{for await(let r of t){if(typeof r!="string"&&!ArrayBuffer.isView(r))throw new TypeError("Invalid chunk: Expected string, TypedArray or Buffer");n.push(r)}return n.finish()}catch(r){throw G(r,n)}}throw new TypeError("Invalid chunk emitter: Expected an Iterable, AsyncIterable, generator, async generator, or a function returning an Iterable or AsyncIterable")}var P=class{constructor(){this.value=void 0,this.valueStack=null,this.stack=new Array(100),this.lastFlushDepth=0,this.flushDepth=0,this.stateString=!1,this.stateStringEscape=!1,this.pendingByteSeq=null,this.pendingChunk=null,this.chunkOffset=0,this.jsonParseOffset=0}parseAndAppend(t,n){this.stack[this.lastFlushDepth-1]===C?(n&&(this.jsonParseOffset--,t="{"+t+"}"),Object.assign(this.valueStack.value,JSON.parse(t))):(n&&(this.jsonParseOffset--,t="["+t+"]"),H(this.valueStack.value,JSON.parse(t)))}prepareAddition(t){let{value:n}=this.valueStack;if(Array.isArray(n)?n.length!==0:Object.keys(n).length!==0){if(t[0]===",")return this.jsonParseOffset++,t.slice(1);if(t[0]!=="}"&&t[0]!=="]")return this.jsonParseOffset-=3,"[[]"+t}return t}flush(t,n,r){let i=t.slice(n,r);if(this.jsonParseOffset=this.chunkOffset+n,this.pendingChunk!==null&&(i=this.pendingChunk+i,this.jsonParseOffset-=this.pendingChunk.length,this.pendingChunk=null),this.flushDepth===this.lastFlushDepth)this.flushDepth>0?this.parseAndAppend(this.prepareAddition(i),!0):(this.value=JSON.parse(i),this.valueStack={value:this.value,prev:null});else if(this.flushDepth>this.lastFlushDepth){for(let s=this.flushDepth-1;s>=this.lastFlushDepth;s--)i+=this.stack[s]===C?"}":"]";this.lastFlushDepth===0?(this.value=JSON.parse(i),this.valueStack={value:this.value,prev:null}):this.parseAndAppend(this.prepareAddition(i),!0);for(let s=this.lastFlushDepth||1;s<this.flushDepth;s++){let l=this.valueStack.value;if(this.stack[s-1]===C){let g;for(g in l);l=l[g]}else l=l[l.length-1];this.valueStack={value:l,prev:this.valueStack}}}else{i=this.prepareAddition(i);for(let s=this.lastFlushDepth-1;s>=this.flushDepth;s--)this.jsonParseOffset--,i=(this.stack[s]===C?"{":"[")+i;this.parseAndAppend(i,!1);for(let s=this.lastFlushDepth-1;s>=this.flushDepth;s--)this.valueStack=this.valueStack.prev}this.lastFlushDepth=this.flushDepth}push(t){if(typeof t!="string"){if(this.pendingByteSeq!==null){let s=t;t=new Uint8Array(this.pendingByteSeq.length+s.length),t.set(this.pendingByteSeq),t.set(s,this.pendingByteSeq.length),this.pendingByteSeq=null}if(t[t.length-1]>127)for(let s=0;s<t.length;s++){let l=t[t.length-1-s];if(l>>6===3){s++,(s!==4&&l>>3===30||s!==3&&l>>4===14||s!==2&&l>>5===6)&&(this.pendingByteSeq=t.slice(t.length-s),t=t.slice(0,-s));break}}t=Y.decode(t)}let n=t.length,r=0,i=0;t:for(let s=0;s<n;s++){if(this.stateString){for(;s<n;s++)if(this.stateStringEscape)this.stateStringEscape=!1;else switch(t.charCodeAt(s)){case 34:this.stateString=!1;continue t;case 92:this.stateStringEscape=!0}break}switch(t.charCodeAt(s)){case 34:this.stateString=!0,this.stateStringEscape=!1;break;case 44:i=s;break;case 123:i=s+1,this.stack[this.flushDepth++]=C;break;case 91:i=s+1,this.stack[this.flushDepth++]=U;break;case 93:case 125:i=s+1,this.flushDepth--,this.flushDepth<this.lastFlushDepth&&(this.flush(t,r,i),r=i);break;case 9:case 10:case 13:case 32:r===s&&r++,i===s&&i++;break}}i>r&&this.flush(t,r,i),i<n&&(this.pendingChunk!==null?this.pendingChunk+=t:this.pendingChunk=t.slice(i,n)),this.chunkOffset+=n}finish(){return this.pendingChunk!==null&&(this.flush("",0,0),this.pendingChunk=null),this.value}};function E(e){return/[^\x20\x21\x23-\x5B\x5D-\uD799]/.test(e)?JSON.stringify(e):'"'+e+'"'}function*m(e,t,n){(t===null||Array.isArray(t)||typeof t!="object")&&(t={replacer:t,space:n});let r=Number(t.highWaterMark)||16384,i=B(t.replacer);n=N(t.space);let s=new Map,l=[],g={"":e},u=null,x=()=>D("",e),y=g,d=!0,h=[""],c=0,a="",k=Object.keys;if(Array.isArray(i)){let f=i;k=()=>f,i=null}for(;x(),!((a.length>=r||u===null)&&(yield a,a="",u===null)););function w(){if(c===0&&(h=k(y),a+="{"),c===h.length){a+=n&&!d?` | ||
${n.repeat(l.length-1)}}`:"}",A();return}let f=h[c++];D(f,y[f])}function o(){if(c===0&&(a+="["),c===y.length){a+=n&&!d?` | ||
${n.repeat(l.length-1)}]`:"]",A();return}D(c,y[c++])}function j(f){if(d?d=!1:a+=",",n&&u!==null&&(a+=` | ||
${n.repeat(l.length)}`),x===w){let p=s.get(f);p===void 0&&s.set(f,p=E(f)+(n?": ":":")),a+=p}}function D(f,p){if(p=F(y,f,p,i),p===null||typeof p!="object")(x!==w||p!==void 0)&&(j(f),b(p));else{if(l.includes(p))throw new TypeError("Converting circular structure to JSON");j(f),l.push(p),S(),x=Array.isArray(p)?o:w,y=p,d=!0,c=0}}function b(f){switch(typeof f){case"string":a+=E(f);break;case"number":a+=Number.isFinite(f)?String(f):"null";break;case"boolean":a+=f?"true":"false";break;case"undefined":case"object":a+="null";break;default:throw new TypeError(`Do not know how to serialize a ${f.constructor?.name||typeof f}`)}}function S(){u={keys:h,index:c,prev:u}}function A(){l.pop();let f=l.length>0?l[l.length-1]:g;x=Array.isArray(f)?o:w,y=f,d=!1,h=u.keys,c=u.index,u=u.prev}}var Q=typeof Object.hasOwn=="function"?Object.hasOwn:(e,t)=>Object.hasOwnProperty.call(e,t),X={8:"\\b",9:"\\t",10:"\\n",12:"\\f",13:"\\r",34:'\\"',92:"\\\\"},Z=Uint8Array.from({length:2048},(e,t)=>Q(X,t)?2:t<32?6:t<128?1:2);function R(e){return e>=55296&&e<=56319}function v(e){return e>=56320&&e<=57343}function T(e){if(!/[^\x20\x21\x23-\x5B\x5D-\x7F]/.test(e))return e.length+2;let t=0,n=!1;for(let r=0;r<e.length;r++){let i=e.charCodeAt(r);if(i<2048)t+=Z[i];else if(R(i)){t+=6,n=!0;continue}else v(i)?t=n?t-2:t+6:t+=3;n=!1}return t+2}function tt(e){let t=0;return e<0&&(t=1,e=-e),e>=1e9&&(t+=9,e=(e-e%1e9)/1e9),e>=1e4?e>=1e6?t+(e>=1e8?9:e>=1e7?8:7):t+(e>=1e5?6:5):t+(e>=100?e>=1e3?4:3:e>=10?2:1)}function et(e){switch(typeof e){case"string":return T(e);case"number":return Number.isFinite(e)?Number.isInteger(e)?tt(e):String(e).length:4;case"boolean":return e?4:5;case"undefined":case"object":return 4;default:return 0}}function nt(e){return e=N(e),typeof e=="string"?e.length:0}function q(e,t,n){(t===null||Array.isArray(t)||typeof t!="object")&&(t={replacer:t,space:n});let r=!!t.continueOnCircular,i=B(t.replacer),s=Object.keys;if(Array.isArray(i)){let k=i;s=()=>k,i=null}n=nt(n);let l=new Map,g=new Map,u=[],x=new Set,y={"":e},d=!1,h=0,c=0;return a(y,"",e),h===0&&(h+=9),{bytes:isNaN(h)?1/0:h,circular:[...x]};function a(k,w,o){if(!d)if(o=F(k,w,o,i),o===null||typeof o!="object")(o!==void 0||Array.isArray(k))&&(h+=et(o));else{if(u.includes(o)){x.add(o),h+=4,r||(d=!0);return}if(g.has(o)){h+=g.get(o);return}c++;let j=c,D=h,b=0;if(u.push(o),Array.isArray(o)){b=o.length;for(let S=0;S<b;S++)a(o,S,o[S])}else{let S=h;for(let A of s(o))if(a(o,A,o[A]),S!==h){let f=l.get(A);f===void 0&&l.set(A,f=T(A)+(n>0?2:1)),h+=f,b++,S=h}}h+=b===0?2:1+b,n>0&&b>0&&(h+=(1+u.length*n)*b+1+(u.length-1)*n),u.pop(),j!==c&&g.set(o,h-D)}}}function J(e){return I(O(e)?e:async function*(){let t=e.getReader();try{for(;;){let{value:n,done:r}=await t.read();if(r)break;yield n}}finally{t.releaseLock()}})}function z(e,t,n){return typeof ReadableStream.from=="function"?ReadableStream.from(m(e,t,n)):new ReadableStream({start(){this.generator=m(e,t,n)},pull(r){let{value:i,done:s}=this.generator.next();s?r.close():r.enqueue(i)},cancel(){this.generator=null}})}return $(it);})(); | ||
@@ -13,0 +12,0 @@ return exports; |
{ | ||
"name": "@discoveryjs/json-ext", | ||
"version": "0.6.0", | ||
"version": "0.6.1", | ||
"description": "A set of utilities that extend the use of JSON", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -92,3 +92,2 @@ # json-ext | ||
```js | ||
import { parseChunked } from '@discoveryjs/json-ext'; | ||
import fs from 'node:fs'; | ||
@@ -132,3 +131,3 @@ | ||
```js | ||
import { stringifyStream } from '@discoveryjs/json-ext'; | ||
import { stringifyChunked } from '@discoveryjs/json-ext'; | ||
@@ -146,2 +145,5 @@ const chunks = [...stringifyChunked(data)]; | ||
```js | ||
import fs from 'node:fs'; | ||
import { Readable } from 'node:stream'; | ||
Readable.from(stringifyChunked(data)) | ||
@@ -152,2 +154,4 @@ .pipe(fs.createWriteStream('path/to/file.json')); | ||
```js | ||
import { Readable } from 'node:stream'; | ||
new Promise((resolve, reject) => { | ||
@@ -161,2 +165,15 @@ Readable.from(stringifyChunked(data)) | ||
``` | ||
- Write into a file synchronously: | ||
> Note: Slower than `JSON.stringify()` but uses much less heap space and has no limitation on string length | ||
```js | ||
import fs from 'node:fs'; | ||
const fd = fs.openSync('output.json', 'w'); | ||
for (const chunk of stringifyChunked(data)) { | ||
fs.writeFileSync(fd, chunk); | ||
} | ||
fs.closeSync(fd); | ||
``` | ||
- Using with fetch (JSON streaming): | ||
@@ -163,0 +180,0 @@ > Note: This feature has limited support in browsers, see [Streaming requests with the fetch API](https://developer.chrome.com/docs/capabilities/web-apis/fetch-streaming-requests) |
@@ -27,8 +27,12 @@ import { | ||
const keyStrings = new Map(); | ||
const visited = []; | ||
const rootValue = { '': value }; | ||
let prevState = null; | ||
let state = () => printEntry('', value); | ||
let stateValue = rootValue; | ||
let stateEmpty = true; | ||
let stateKeys = ['']; | ||
let stateIndex = 0; | ||
let buffer = ''; | ||
let depth = 0; | ||
let stack = null; | ||
let first = false; | ||
let visited = new WeakSet(); | ||
let processing = false; | ||
let getKeys = Object.keys; | ||
@@ -43,124 +47,99 @@ | ||
pushStack(processRoot, value, null); | ||
while (true) { | ||
state(); | ||
while (stack !== null) { | ||
processing = true; | ||
if (buffer.length >= highWaterMark || prevState === null) { | ||
// flush buffer | ||
yield buffer; | ||
buffer = ''; | ||
while (stack !== null && !stack.awaiting) { | ||
stack.handler(); | ||
if (!processing) { | ||
if (prevState === null) { | ||
break; | ||
} | ||
} | ||
processing = false; | ||
// flush buffer | ||
yield buffer; | ||
buffer = ''; | ||
} | ||
function processRoot() { | ||
const { value } = stack; | ||
function printObject() { | ||
if (stateIndex === 0) { | ||
stateKeys = getKeys(stateValue); | ||
buffer += '{'; | ||
} | ||
popStack(); | ||
processValue({ '': value }, '', value, () => {}); | ||
} | ||
// when no keys left | ||
if (stateIndex === stateKeys.length) { | ||
buffer += space && !stateEmpty | ||
? `\n${space.repeat(visited.length - 1)}}` | ||
: '}'; | ||
function processObjectEntry(key) { | ||
if (first === false) { | ||
first = true; | ||
} else { | ||
push(','); | ||
popState(); | ||
return; | ||
} | ||
if (space) { | ||
push(`\n${space.repeat(depth)}${encodeString(key)}: `); | ||
} else { | ||
push(encodeString(key) + ':'); | ||
} | ||
const key = stateKeys[stateIndex++]; | ||
printEntry(key, stateValue[key]); | ||
} | ||
function processObject() { | ||
const current = stack; | ||
function printArray() { | ||
if (stateIndex === 0) { | ||
buffer += '['; | ||
} | ||
// when no keys left, remove obj from stack | ||
if (current.index === current.keys.length) { | ||
if (space && first) { | ||
push(`\n${space.repeat(depth - 1)}}`); | ||
} else { | ||
push('}'); | ||
} | ||
if (stateIndex === stateValue.length) { | ||
buffer += space && !stateEmpty | ||
? `\n${space.repeat(visited.length - 1)}]` | ||
: ']'; | ||
popStack(); | ||
popState(); | ||
return; | ||
} | ||
const key = current.keys[current.index]; | ||
processValue(current.value, key, current.value[key], processObjectEntry); | ||
current.index++; | ||
printEntry(stateIndex, stateValue[stateIndex++]); | ||
} | ||
function processArrayItem(index) { | ||
if (index !== 0) { | ||
push(','); | ||
function printEntryPrelude(key) { | ||
if (stateEmpty) { | ||
stateEmpty = false; | ||
} else { | ||
buffer += ','; | ||
} | ||
if (space) { | ||
push(`\n${space.repeat(depth)}`); | ||
if (space && prevState !== null) { | ||
buffer += `\n${space.repeat(visited.length)}`; | ||
} | ||
} | ||
function processArray() { | ||
const current = stack; | ||
if (state === printObject) { | ||
let keyString = keyStrings.get(key); | ||
if (current.index === current.value.length) { | ||
if (space && current.index !== 0) { | ||
push(`\n${space.repeat(depth - 1)}]`); | ||
} else { | ||
push(']'); | ||
if (keyString === undefined) { | ||
keyStrings.set(key, keyString = encodeString(key) + (space ? ': ' : ':')); | ||
} | ||
popStack(); | ||
return; | ||
buffer += keyString; | ||
} | ||
processValue(current.value, current.index, current.value[current.index], processArrayItem); | ||
current.index++; | ||
} | ||
function processValue(holder, key, value, callback) { | ||
value = replaceValue(holder, key, value, replacer); | ||
function printEntry(key, value) { | ||
value = replaceValue(stateValue, key, value, replacer); | ||
if (value === null || typeof value !== 'object') { | ||
// primitive | ||
if (callback !== processObjectEntry || value !== undefined) { | ||
callback(key); | ||
if (state !== printObject || value !== undefined) { | ||
printEntryPrelude(key); | ||
pushPrimitive(value); | ||
} | ||
} else if (Array.isArray(value)) { | ||
// array | ||
callback(key); | ||
circularCheck(value); | ||
depth++; | ||
push('['); | ||
pushStack(processArray, value, null); | ||
} else { | ||
// object | ||
callback(key); | ||
circularCheck(value); | ||
depth++; | ||
push('{'); | ||
pushStack(processObject, value, getKeys(value)); | ||
} | ||
} | ||
// If the visited set does not change after adding a value, then it is already in the set | ||
if (visited.includes(value)) { | ||
throw new TypeError('Converting circular structure to JSON'); | ||
} | ||
function circularCheck(value) { | ||
if (visited.has(value)) { | ||
throw new TypeError('Converting circular structure to JSON'); | ||
printEntryPrelude(key); | ||
visited.push(value); | ||
pushState(); | ||
state = Array.isArray(value) ? printArray : printObject; | ||
stateValue = value; | ||
stateEmpty = true; | ||
stateIndex = 0; | ||
} | ||
visited.add(value); | ||
} | ||
@@ -171,11 +150,11 @@ | ||
case 'string': | ||
push(encodeString(value)); | ||
buffer += encodeString(value); | ||
break; | ||
case 'number': | ||
push(Number.isFinite(value) ? value : 'null'); | ||
buffer += Number.isFinite(value) ? String(value) : 'null'; | ||
break; | ||
case 'boolean': | ||
push(value ? 'true' : 'false'); | ||
buffer += value ? 'true' : 'false'; | ||
break; | ||
@@ -185,3 +164,3 @@ | ||
case 'object': // typeof null === 'object' | ||
push('null'); | ||
buffer += 'null'; | ||
break; | ||
@@ -194,29 +173,24 @@ | ||
function pushStack(handler, value, keys) { | ||
first = false; | ||
return stack = { | ||
handler, | ||
value, | ||
index: 0, | ||
keys, | ||
prev: stack | ||
function pushState() { | ||
prevState = { | ||
keys: stateKeys, | ||
index: stateIndex, | ||
prev: prevState | ||
}; | ||
} | ||
function popStack() { | ||
const { handler, value } = stack; | ||
function popState() { | ||
visited.pop(); | ||
const value = visited.length > 0 ? visited[visited.length - 1] : rootValue; | ||
if (handler === processObject || handler === processArray) { | ||
visited.delete(value); | ||
depth--; | ||
} | ||
// restore state | ||
state = Array.isArray(value) ? printArray : printObject; | ||
stateValue = value; | ||
stateEmpty = false; | ||
stateKeys = prevState.keys; | ||
stateIndex = prevState.index; | ||
stack = stack.prev; | ||
first = true; | ||
// pop state | ||
prevState = prevState.prev; | ||
} | ||
function push(data) { | ||
buffer += data; | ||
processing = buffer.length < highWaterMark; | ||
} | ||
}; |
@@ -22,3 +22,3 @@ import { | ||
const charLength2048 = Array.from({ length: 2048 }).map((_, code) => { | ||
const charLength2048 = Uint8Array.from({ length: 2048 }, (_, code) => { | ||
if (hasOwn(escapableCharCodeSubstitution, code)) { | ||
@@ -44,2 +44,7 @@ return 2; // \X | ||
function stringLength(str) { | ||
// Fast path to compute length when a string contains only characters encoded as single bytes | ||
if (!/[^\x20\x21\x23-\x5B\x5D-\x7F]/.test(str)) { | ||
return str.length + 2; | ||
} | ||
let len = 0; | ||
@@ -71,2 +76,32 @@ let prevLeadingSurrogate = false; | ||
// avoid producing a string from a number | ||
function intLength(num) { | ||
let len = 0; | ||
if (num < 0) { | ||
len = 1; | ||
num = -num; | ||
} | ||
if (num >= 1e9) { | ||
len += 9; | ||
num = (num - num % 1e9) / 1e9; | ||
} | ||
if (num >= 1e4) { | ||
if (num >= 1e6) { | ||
return len + (num >= 1e8 | ||
? 9 | ||
: num >= 1e7 ? 8 : 7 | ||
); | ||
} | ||
return len + (num >= 1e5 ? 6 : 5); | ||
} | ||
return len + (num >= 1e2 | ||
? num >= 1e3 ? 4 : 3 | ||
: num >= 10 ? 2 : 1 | ||
); | ||
}; | ||
function primitiveLength(value) { | ||
@@ -78,3 +113,7 @@ switch (typeof value) { | ||
case 'number': | ||
return Number.isFinite(value) ? String(value).length : 4 /* null */; | ||
return Number.isFinite(value) | ||
? Number.isInteger(value) | ||
? intLength(value) | ||
: String(value).length | ||
: 4 /* null */; | ||
@@ -106,8 +145,10 @@ case 'boolean': | ||
let allowlist = null; | ||
const continueOnCircular = Boolean(optionsOrReplacer.continueOnCircular); | ||
let replacer = normalizeReplacer(optionsOrReplacer.replacer); | ||
const continueOnCircular = Boolean(optionsOrReplacer.continueOnCircular); | ||
let getKeys = Object.keys; | ||
if (Array.isArray(replacer)) { | ||
allowlist = new Set(replacer); | ||
const allowlist = replacer; | ||
getKeys = () => allowlist; | ||
replacer = null; | ||
@@ -118,4 +159,5 @@ } | ||
const visited = new WeakMap(); | ||
const stack = new Set(); | ||
const keysLength = new Map(); | ||
const visited = new Map(); | ||
const stack = []; | ||
const circular = new Set(); | ||
@@ -125,5 +167,11 @@ const root = { '': value }; | ||
let bytes = 0; | ||
let objects = 0; | ||
walk(root, '', value); | ||
// when value is undefined or replaced for undefined | ||
if (bytes === 0) { | ||
bytes += 9; // FIXME: that's the length of undefined, should we normalize behaviour to convert it to null? | ||
} | ||
return { | ||
@@ -145,8 +193,6 @@ bytes: isNaN(bytes) ? Infinity : bytes, | ||
bytes += primitiveLength(value); | ||
} else if (holder === root) { | ||
bytes += 9; // FIXME: that's the length of undefined, should we normalize behaviour to convert it to null? | ||
} | ||
} else { | ||
// check for circular structure | ||
if (stack.has(value)) { | ||
// check for circular references | ||
if (stack.includes(value)) { | ||
circular.add(value); | ||
@@ -162,3 +208,5 @@ bytes += 4; // treat as null | ||
// duplicates | ||
// Using 'visited' allows avoiding hang-ups in cases of highly interconnected object graphs; | ||
// for example, a list of git commits with references to parents can lead to N^2 complexity for traversal, | ||
// and N when 'visited' is used | ||
if (visited.has(value)) { | ||
@@ -170,60 +218,54 @@ bytes += visited.get(value); | ||
objects++; | ||
const prevObjects = objects; | ||
const valueBytes = bytes; | ||
let valueLength = 0; | ||
stack.push(value); | ||
if (Array.isArray(value)) { | ||
// array | ||
const valueLength = bytes; | ||
valueLength = value.length; | ||
bytes += 2; // [] | ||
stack.add(value); | ||
for (let i = 0; i < value.length; i++) { | ||
for (let i = 0; i < valueLength; i++) { | ||
walk(value, i, value[i]); | ||
} | ||
if (value.length > 1) { | ||
bytes += value.length - 1; // commas | ||
} | ||
stack.delete(value); | ||
if (space > 0 && value.length > 0) { | ||
bytes += (1 + (stack.size + 1) * space) * value.length; // for each element: \n{space} | ||
bytes += 1 + stack.size * space; // for ] | ||
} | ||
visited.set(value, bytes - valueLength); | ||
} else { | ||
// object | ||
const valueLength = bytes; | ||
let entries = 0; | ||
let prevLength = bytes; | ||
bytes += 2; // {} | ||
for (const key of getKeys(value)) { | ||
walk(value, key, value[key]); | ||
stack.add(value); | ||
if (prevLength !== bytes) { | ||
let keyLen = keysLength.get(key); | ||
for (const key in value) { | ||
if (hasOwn(value, key) && (allowlist === null || allowlist.has(key))) { | ||
const prevLength = bytes; | ||
walk(value, key, value[key]); | ||
if (keyLen === undefined) { | ||
keysLength.set(key, keyLen = stringLength(key) + (space > 0 ? 2 : 1)); // "key": | ||
} | ||
if (prevLength !== bytes) { | ||
// value is printed | ||
bytes += stringLength(key) + 1; // "key": | ||
entries++; | ||
} | ||
// value is printed | ||
bytes += keyLen; | ||
valueLength++; | ||
prevLength = bytes; | ||
} | ||
} | ||
} | ||
if (entries > 1) { | ||
bytes += entries - 1; // commas | ||
} | ||
bytes += valueLength === 0 | ||
? 2 // {} or [] | ||
: 1 + valueLength; // {} or [] + commas | ||
stack.delete(value); | ||
if (space > 0 && valueLength > 0) { | ||
bytes += | ||
(1 + stack.length * space) * valueLength + // for each key-value: \n{space} | ||
1 + (stack.length - 1) * space; // for } | ||
} | ||
if (space > 0 && entries > 0) { | ||
bytes += (1 + (stack.size + 1) * space + 1) * entries; // for each key-value: \n{space} | ||
bytes += 1 + stack.size * space; // for } | ||
} | ||
stack.pop(); | ||
visited.set(value, bytes - valueLength); | ||
// add to 'visited' only objects that contain nested objects | ||
if (prevObjects !== objects) { | ||
visited.set(value, bytes - valueBytes); | ||
} | ||
@@ -230,0 +272,0 @@ } |
@@ -13,10 +13,14 @@ /* eslint-env browser */ | ||
while (true) { | ||
const { value, done } = await reader.read(); | ||
try { | ||
while (true) { | ||
const { value, done } = await reader.read(); | ||
if (done) { | ||
break; | ||
if (done) { | ||
break; | ||
} | ||
yield value; | ||
} | ||
yield value; | ||
} finally { | ||
reader.releaseLock(); | ||
} | ||
@@ -23,0 +27,0 @@ }); |
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
146004
2326
274
0