Skip to content

Commit 964e3f6

Browse files
committed
Added bigint.
1 parent c604962 commit 964e3f6

7 files changed

Lines changed: 111 additions & 15 deletions

File tree

llms-full.txt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,8 @@ Browser-safe Web-only entry: `stream-json/web/disassembler.js` (no Node-stream i
280280
Options: same as Parser (`packKeys`, `packStrings`, `packNumbers`, `streamKeys`, `streamStrings`, `streamNumbers`, `packValues`, `streamValues`). Also:
281281
- `replacer` (function or array) — like `JSON.stringify` replacer.
282282

283+
Value handling follows `JSON.stringify`: `toJSON()` is honored; functions, symbols, and `undefined` are skipped in objects and become `null` in arrays; `NaN` and `±Infinity` become `null`. Exception: `bigint` is emitted as number tokens with all digits intact (JSON has no magnitude limit) instead of throwing.
284+
283285
```js
284286
import {disassembler} from 'stream-json/disassembler.js';
285287
import {stringer} from 'stream-json/stringer.js';
@@ -426,9 +428,10 @@ Replaces matching subobjects with a replacement value.
426428

427429
Extra option:
428430
- `replacement` — the replacement:
429-
- **function** `(stack, chunk, options) => value` — dynamic replacement.
430-
- **value** — static replacement value (converted to tokens).
431+
- **function** `(stack, chunk, options) => tokens` — dynamic replacement; return `none` to remove the value.
432+
- **token** — a single static token, such as `{name: 'nullValue', value: null}`.
431433
- **array** — array of tokens to insert.
434+
- Anything else, including `null`, removes the value.
432435
- Default: `none` (removes the value, replaced by nothing).
433436

434437
```js

llms.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ e.addEventListener('keyValue', ev => console.log(ev.detail));
121121
All filters accept `{filter, pathSeparator, once, streamKeys, maxDepth}` options. `filter` can be a string, RegExp, or `(stack, chunk) => boolean`. `maxDepth` caps the JSON nesting depth a filter evaluates (default `1024`; a deeper token throws a `RangeError`, `Infinity` disables the limit).
122122

123123
- **`pick(options)`** — passes only matching subobjects, discards the rest.
124-
- **`replace(options)`** — replaces matching subobjects. Extra option: `replacement` (function, value, or array of tokens).
124+
- **`replace(options)`** — replaces matching subobjects. Extra option: `replacement` (function, token, or array of tokens).
125125
- **`ignore(options)`** — removes matching subobjects completely.
126126
- **`filter(options)`** — keeps matching subobjects preserving surrounding structure.
127127

src/core/disassembler.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import type parser from './parser.js';
55
*
66
* The inverse of the parser: takes JS values and produces `{name, value}` tokens
77
* following the same protocol. Supports `JSON.stringify()`-compatible `replacer` and `toJSON()`.
8+
* `bigint` values become number tokens with all digits intact (JSON has no magnitude limit;
9+
* `JSON.stringify()` throws instead).
810
*
911
* This is the pure, stream-agnostic factory — no `.asStream` / `.asWebStream` adapters
1012
* attached. For the Node-flavored entry (with both adapters) import from

src/core/disassembler.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ function* dump(value, options, processed) {
1414
case 'function':
1515
case 'symbol':
1616
case 'undefined':
17-
case 'bigint':
1817
return;
1918
case 'number':
2019
if (isNaN(value) || !isFinite(value)) {
2120
yield {name: 'nullValue', value: null};
2221
return;
2322
}
23+
// falls through
24+
case 'bigint':
2425
value = String(value);
2526
if (options.streamNumbers) {
2627
yield {name: 'startNumber'};
@@ -71,7 +72,6 @@ function* dump(value, options, processed) {
7172
case 'function':
7273
case 'symbol':
7374
case 'undefined':
74-
case 'bigint':
7575
v = null; // force null
7676
break;
7777
}
@@ -95,7 +95,6 @@ function* dump(value, options, processed) {
9595
case 'function':
9696
case 'symbol':
9797
case 'undefined':
98-
case 'bigint':
9998
continue;
10099
}
101100
if (options.streamKeys) {

tests/node/test-disassembler.js

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import disassembler from '../../src/disassembler.js';
66
import pick from '../../src/filters/pick.js';
77
import streamArray from '../../src/streamers/stream-array.js';
88
import streamValues from '../../src/streamers/stream-values.js';
9+
import {stringer} from '../../src/stringer.js';
910

1011
import {readString} from '../helpers.js';
1112

@@ -33,7 +34,7 @@ test.asPromise('disassembler: roundtrip', (t, resolve, reject) => {
3334
});
3435

3536
test.asPromise('disassembler: bad top-level values', (t, resolve, reject) => {
36-
const input = [1, () => {}, 2, undefined, 3, Symbol(), 4, 5n],
37+
const input = [1, () => {}, 2, undefined, 3, Symbol(), 4],
3738
result = [],
3839
pipeline = chain([disassembler(), streamValues()]);
3940

@@ -51,7 +52,7 @@ test.asPromise('disassembler: bad top-level values', (t, resolve, reject) => {
5152
});
5253

5354
test.asPromise('disassembler: bad values in object', (t, resolve, reject) => {
54-
const input = [{a: 1, b: () => {}, c: 2, d: undefined, e: 3, f: Symbol(), g: 4, h: 5n}],
55+
const input = [{a: 1, b: () => {}, c: 2, d: undefined, e: 3, f: Symbol(), g: 4}],
5556
result = [],
5657
pipeline = chain([disassembler(), streamValues()]);
5758

@@ -69,14 +70,14 @@ test.asPromise('disassembler: bad values in object', (t, resolve, reject) => {
6970
});
7071

7172
test.asPromise('disassembler: bad values in array', (t, resolve, reject) => {
72-
const input = [[1, () => {}, 2, undefined, 3, Symbol(), 4, 5n]],
73+
const input = [[1, () => {}, 2, undefined, 3, Symbol(), 4]],
7374
result = [],
7475
pipeline = chain([disassembler(), streamValues()]);
7576

7677
pipeline.on('data', item => result.push(item.value));
7778
pipeline.on('error', reject);
7879
pipeline.on('end', () => {
79-
t.deepEqual(result, [[1, null, 2, null, 3, null, 4, null]]);
80+
t.deepEqual(result, [[1, null, 2, null, 3, null, 4]]);
8081
resolve();
8182
});
8283

@@ -295,3 +296,51 @@ test('disassembler: -Infinity yields only nullValue', t => {
295296
t.equal(tokens[0].name, 'nullValue');
296297
t.equal(tokens[0].value, null);
297298
});
299+
300+
test('disassembler: bigint yields number tokens with all digits', t => {
301+
const fn = disassembler();
302+
t.deepEqual(
303+
[...fn(12345678901234567890n)],
304+
[{name: 'startNumber'}, {name: 'numberChunk', value: '12345678901234567890'}, {name: 'endNumber'}, {name: 'numberValue', value: '12345678901234567890'}]
305+
);
306+
});
307+
308+
test('disassembler: bigint streamValues=false yields only numberValue', t => {
309+
const fn = disassembler({streamValues: false});
310+
t.deepEqual([...fn(-5n)], [{name: 'numberValue', value: '-5'}]);
311+
});
312+
313+
test('disassembler: bigint in containers', t => {
314+
const fn = disassembler({streamValues: false});
315+
t.deepEqual(
316+
[...fn({a: 1n, b: [2n]})],
317+
[
318+
{name: 'startObject'},
319+
{name: 'keyValue', value: 'a'},
320+
{name: 'numberValue', value: '1'},
321+
{name: 'keyValue', value: 'b'},
322+
{name: 'startArray'},
323+
{name: 'numberValue', value: '2'},
324+
{name: 'endArray'},
325+
{name: 'endObject'}
326+
]
327+
);
328+
});
329+
330+
test.asPromise('disassembler: bigint round trip through stringer', (t, resolve, reject) => {
331+
const input = [{a: 12345678901234567890n, b: [-1n, 9007199254740993n]}];
332+
let buffer = '';
333+
const pipeline = chain([disassembler(), stringer()]);
334+
335+
pipeline.on('data', data => (buffer += data));
336+
pipeline.on('error', reject);
337+
pipeline.on('end', () => {
338+
t.equal(buffer, '{"a":12345678901234567890,"b":[-1,9007199254740993]}');
339+
resolve();
340+
});
341+
342+
for (const item of input) {
343+
pipeline.write(item);
344+
}
345+
pipeline.end();
346+
});

tests/web/test-disassembler.js

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import disassembler from '../../src/web/disassembler.js';
99
import pick from '../../src/web/filters/pick.js';
1010
import streamArray from '../../src/web/streamers/stream-array.js';
1111
import streamValues from '../../src/web/streamers/stream-values.js';
12+
import {stringer} from '../../src/web/stringer.js';
1213

1314
import {readWebString, drain} from '../web-helpers.js';
1415

@@ -49,7 +50,7 @@ test.asPromise('disassembler (web): roundtrip', async (t, resolve, reject) => {
4950

5051
test.asPromise('disassembler (web): bad top-level values', async (t, resolve, reject) => {
5152
try {
52-
const input = [1, () => {}, 2, undefined, 3, Symbol(), 4, 5n];
53+
const input = [1, () => {}, 2, undefined, 3, Symbol(), 4];
5354
const pipeline = chain([fromArray(input), disassembler(), streamValues()]);
5455
const out = await drain(pipeline);
5556
const result = out.map(item => item.value);
@@ -62,7 +63,7 @@ test.asPromise('disassembler (web): bad top-level values', async (t, resolve, re
6263

6364
test.asPromise('disassembler (web): bad values in object', async (t, resolve, reject) => {
6465
try {
65-
const input = [{a: 1, b: () => {}, c: 2, d: undefined, e: 3, f: Symbol(), g: 4, h: 5n}];
66+
const input = [{a: 1, b: () => {}, c: 2, d: undefined, e: 3, f: Symbol(), g: 4}];
6667
const pipeline = chain([fromArray(input), disassembler(), streamValues()]);
6768
const out = await drain(pipeline);
6869
const result = out.map(item => item.value);
@@ -75,11 +76,11 @@ test.asPromise('disassembler (web): bad values in object', async (t, resolve, re
7576

7677
test.asPromise('disassembler (web): bad values in array', async (t, resolve, reject) => {
7778
try {
78-
const input = [[1, () => {}, 2, undefined, 3, Symbol(), 4, 5n]];
79+
const input = [[1, () => {}, 2, undefined, 3, Symbol(), 4]];
7980
const pipeline = chain([fromArray(input), disassembler(), streamValues()]);
8081
const out = await drain(pipeline);
8182
const result = out.map(item => item.value);
82-
t.deepEqual(result, [[1, null, 2, null, 3, null, 4, null]]);
83+
t.deepEqual(result, [[1, null, 2, null, 3, null, 4]]);
8384
resolve();
8485
} catch (e) {
8586
reject(e);
@@ -258,3 +259,45 @@ test('disassembler (web): -Infinity yields only nullValue', t => {
258259
t.equal(tokens[0].name, 'nullValue');
259260
t.equal(tokens[0].value, null);
260261
});
262+
263+
test('disassembler (web): bigint yields number tokens with all digits', t => {
264+
const fn = disassembler();
265+
t.deepEqual(
266+
[...fn(12345678901234567890n)],
267+
[{name: 'startNumber'}, {name: 'numberChunk', value: '12345678901234567890'}, {name: 'endNumber'}, {name: 'numberValue', value: '12345678901234567890'}]
268+
);
269+
});
270+
271+
test('disassembler (web): bigint streamValues=false yields only numberValue', t => {
272+
const fn = disassembler({streamValues: false});
273+
t.deepEqual([...fn(-5n)], [{name: 'numberValue', value: '-5'}]);
274+
});
275+
276+
test('disassembler (web): bigint in containers', t => {
277+
const fn = disassembler({streamValues: false});
278+
t.deepEqual(
279+
[...fn({a: 1n, b: [2n]})],
280+
[
281+
{name: 'startObject'},
282+
{name: 'keyValue', value: 'a'},
283+
{name: 'numberValue', value: '1'},
284+
{name: 'keyValue', value: 'b'},
285+
{name: 'startArray'},
286+
{name: 'numberValue', value: '2'},
287+
{name: 'endArray'},
288+
{name: 'endObject'}
289+
]
290+
);
291+
});
292+
293+
test.asPromise('disassembler (web): bigint round trip through stringer', async (t, resolve, reject) => {
294+
try {
295+
const input = [{a: 12345678901234567890n, b: [-1n, 9007199254740993n]}];
296+
const pipeline = chain([fromArray(input), disassembler(), stringer()]);
297+
const out = await drain(pipeline);
298+
t.equal(out.join(''), '{"a":12345678901234567890,"b":[-1,9007199254740993]}');
299+
resolve();
300+
} catch (e) {
301+
reject(e);
302+
}
303+
});

wiki

Submodule wiki updated from 91e4a90 to b77ae0f

0 commit comments

Comments
 (0)