node-modules-tools 2.1.2 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/index.mjs +3 -4
- package/dist/chunks/json-parse-stream.mjs +2251 -1603
- package/dist/constants.d.mts +2 -2
- package/dist/constants.d.ts +2 -2
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +3 -3
- package/dist/shared/{node-modules-tools.w8TD_NJZ.d.mts → node-modules-tools.6PktBjdw.d.mts} +3 -3
- package/dist/shared/{node-modules-tools.VxxuULZa.mjs → node-modules-tools.CFlGcN5v.mjs} +1 -1
- package/dist/shared/{node-modules-tools.B4jDG218.d.ts → node-modules-tools.CRCdEV1U.d.ts} +3 -3
- package/dist/shared/{node-modules-tools.BUfYtQgm.d.mts → node-modules-tools.hoWqUakN.d.mts} +1 -1
- package/dist/shared/{node-modules-tools.BUfYtQgm.d.ts → node-modules-tools.hoWqUakN.d.ts} +1 -1
- package/dist/utils.d.mts +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.mjs +2 -2
- package/package.json +7 -7
|
@@ -1,1617 +1,2265 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { Duplex, Readable, Writable } from 'node:stream';
|
|
2
|
+
|
|
3
|
+
// @ts-self-types="./defs.d.ts"
|
|
4
|
+
|
|
5
|
+
const none = Symbol.for('object-stream.none');
|
|
6
|
+
const stop = Symbol.for('object-stream.stop');
|
|
7
|
+
|
|
8
|
+
const finalSymbol = Symbol.for('object-stream.final');
|
|
9
|
+
const manySymbol = Symbol.for('object-stream.many');
|
|
10
|
+
const flushSymbol = Symbol.for('object-stream.flush');
|
|
11
|
+
const fListSymbol = Symbol.for('object-stream.fList');
|
|
12
|
+
|
|
13
|
+
const finalValue = value => ({[finalSymbol]: 1, value});
|
|
14
|
+
const many = values => ({[manySymbol]: 1, values});
|
|
15
|
+
|
|
16
|
+
const isFinalValue = o => o && o[finalSymbol] === 1;
|
|
17
|
+
const isMany = o => o && o[manySymbol] === 1;
|
|
18
|
+
const isFlushable = o => o && o[flushSymbol] === 1;
|
|
19
|
+
const isFunctionList = o => o && o[fListSymbol] === 1;
|
|
20
|
+
|
|
21
|
+
const getFinalValue = o => o.value;
|
|
22
|
+
const getManyValues = o => o.values;
|
|
23
|
+
const getFunctionList = o => o.fList;
|
|
24
|
+
|
|
25
|
+
const flushable = (write, final = null) => {
|
|
26
|
+
const fn = final ? value => (value === none ? final() : write(value)) : write;
|
|
27
|
+
fn[flushSymbol] = 1;
|
|
28
|
+
return fn;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const setFunctionList = (o, fns) => {
|
|
32
|
+
o.fList = fns;
|
|
33
|
+
o[fListSymbol] = 1;
|
|
34
|
+
return o;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const clearFunctionList = o => {
|
|
38
|
+
delete o.fList;
|
|
39
|
+
delete o[fListSymbol];
|
|
40
|
+
return o;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
class Stop extends Error {}
|
|
44
|
+
|
|
45
|
+
const toMany = value =>
|
|
46
|
+
value === none ? many([]) : value && value[manySymbol] === 1 ? value : many([value]);
|
|
47
|
+
|
|
48
|
+
const normalizeMany = o => {
|
|
49
|
+
if (o?.[manySymbol] === 1) {
|
|
50
|
+
switch (o.values.length) {
|
|
51
|
+
case 0:
|
|
52
|
+
return none;
|
|
53
|
+
case 1:
|
|
54
|
+
return o.values[0];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return o;
|
|
58
|
+
};
|
|
3
59
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
60
|
+
const combineMany = (...args) => {
|
|
61
|
+
const values = [];
|
|
62
|
+
for (let i = 0; i < args.length; ++i) {
|
|
63
|
+
const a = args[i];
|
|
64
|
+
if (a === none) continue;
|
|
65
|
+
if (a?.[manySymbol] === 1) {
|
|
66
|
+
values.push(...a.values);
|
|
67
|
+
} else {
|
|
68
|
+
values.push(a);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return many(values);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const combineManyMut = (a, ...args) => {
|
|
75
|
+
const values = a === none ? [] : a?.[manySymbol] === 1 ? a.values : [a];
|
|
76
|
+
for (let i = 0; i < args.length; ++i) {
|
|
77
|
+
const b = args[i];
|
|
78
|
+
if (b === none) continue;
|
|
79
|
+
if (b?.[manySymbol] === 1) {
|
|
80
|
+
values.push(...b.values);
|
|
81
|
+
} else {
|
|
82
|
+
values.push(b);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return many(values);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// Stream type guards (shape-based). Live in defs.js so the symmetric
|
|
90
|
+
// is*WebStream and is*NodeStream are co-located and reachable from any
|
|
91
|
+
// subpath. Neither path imports `node:stream` — both are duck-typed:
|
|
92
|
+
//
|
|
93
|
+
// - Web: ReadableStream has `getReader`, WritableStream has `getWriter`
|
|
94
|
+
// (Node streams expose neither).
|
|
95
|
+
// - Node: streams expose `.pipe` / `.write` / `.on` plus the private
|
|
96
|
+
// `_readableState` / `_writableState` markers (Web streams expose none).
|
|
97
|
+
//
|
|
98
|
+
// Node guard logic is taken from
|
|
99
|
+
// https://github.com/nodejs/node/blob/master/lib/internal/streams/utils.js
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
const isReadableWebStream$1 = x =>
|
|
103
|
+
!!(
|
|
104
|
+
x &&
|
|
105
|
+
typeof x === 'object' &&
|
|
106
|
+
typeof x.getReader === 'function' &&
|
|
107
|
+
typeof x.pipeTo === 'function'
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const isWritableWebStream$1 = x =>
|
|
111
|
+
!!(
|
|
112
|
+
x &&
|
|
113
|
+
typeof x === 'object' &&
|
|
114
|
+
typeof x.getWriter === 'function' &&
|
|
115
|
+
typeof x.abort === 'function'
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const isDuplexWebStream$1 = x =>
|
|
119
|
+
!!(
|
|
120
|
+
x &&
|
|
121
|
+
typeof x === 'object' &&
|
|
122
|
+
isReadableWebStream$1(x.readable) &&
|
|
123
|
+
isWritableWebStream$1(x.writable)
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const isReadableNodeStream$1 = obj =>
|
|
127
|
+
obj &&
|
|
128
|
+
typeof obj.pipe === 'function' &&
|
|
129
|
+
typeof obj.on === 'function' &&
|
|
130
|
+
(!obj._writableState ||
|
|
131
|
+
(typeof obj._readableState === 'object' ? obj._readableState.readable : null) !== false) &&
|
|
132
|
+
(!obj._writableState || obj._readableState);
|
|
133
|
+
|
|
134
|
+
const isWritableNodeStream$1 = obj =>
|
|
135
|
+
obj &&
|
|
136
|
+
typeof obj.write === 'function' &&
|
|
137
|
+
typeof obj.on === 'function' &&
|
|
138
|
+
(!obj._readableState ||
|
|
139
|
+
(typeof obj._writableState === 'object' ? obj._writableState.writable : null) !== false);
|
|
140
|
+
|
|
141
|
+
const isDuplexNodeStream$1 = obj =>
|
|
142
|
+
obj &&
|
|
143
|
+
typeof obj.pipe === 'function' &&
|
|
144
|
+
obj._readableState &&
|
|
145
|
+
typeof obj.on === 'function' &&
|
|
146
|
+
typeof obj.write === 'function';
|
|
147
|
+
|
|
148
|
+
// old aliases
|
|
149
|
+
const final$1 = finalValue;
|
|
150
|
+
|
|
151
|
+
const defs = {
|
|
152
|
+
__proto__: null,
|
|
153
|
+
Stop: Stop,
|
|
154
|
+
clearFunctionList: clearFunctionList,
|
|
155
|
+
combineMany: combineMany,
|
|
156
|
+
combineManyMut: combineManyMut,
|
|
157
|
+
fListSymbol: fListSymbol,
|
|
158
|
+
final: final$1,
|
|
159
|
+
finalSymbol: finalSymbol,
|
|
160
|
+
finalValue: finalValue,
|
|
161
|
+
flushSymbol: flushSymbol,
|
|
162
|
+
flushable: flushable,
|
|
163
|
+
getFinalValue: getFinalValue,
|
|
164
|
+
getFunctionList: getFunctionList,
|
|
165
|
+
getManyValues: getManyValues,
|
|
166
|
+
isDuplexNodeStream: isDuplexNodeStream$1,
|
|
167
|
+
isDuplexWebStream: isDuplexWebStream$1,
|
|
168
|
+
isFinalValue: isFinalValue,
|
|
169
|
+
isFlushable: isFlushable,
|
|
170
|
+
isFunctionList: isFunctionList,
|
|
171
|
+
isMany: isMany,
|
|
172
|
+
isReadableNodeStream: isReadableNodeStream$1,
|
|
173
|
+
isReadableWebStream: isReadableWebStream$1,
|
|
174
|
+
isWritableNodeStream: isWritableNodeStream$1,
|
|
175
|
+
isWritableWebStream: isWritableWebStream$1,
|
|
176
|
+
many: many,
|
|
177
|
+
manySymbol: manySymbol,
|
|
178
|
+
none: none,
|
|
179
|
+
normalizeMany: normalizeMany,
|
|
180
|
+
setFunctionList: setFunctionList,
|
|
181
|
+
stop: stop,
|
|
182
|
+
toMany: toMany
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// @ts-self-types="./exec.d.ts"
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
const next = (value, fns, index, push) => {
|
|
189
|
+
for (let i = index; ; ) {
|
|
190
|
+
if (value && typeof value.then == 'function') {
|
|
191
|
+
const ii = i;
|
|
192
|
+
return value.then(v => next(v, fns, ii, push));
|
|
193
|
+
}
|
|
194
|
+
if (value == null || value === none) return;
|
|
195
|
+
if (value === stop) throw new Stop();
|
|
196
|
+
if (isFinalValue(value)) {
|
|
197
|
+
return push(getFinalValue(value)); // emit, bypass remaining fns
|
|
198
|
+
}
|
|
199
|
+
if (isMany(value)) {
|
|
200
|
+
return nextMany(getManyValues(value), fns, i, push);
|
|
201
|
+
}
|
|
202
|
+
if (value && typeof value.next == 'function') {
|
|
203
|
+
return nextGen(value, fns, i, push);
|
|
204
|
+
}
|
|
205
|
+
if (i >= fns.length) {
|
|
206
|
+
return push(value); // terminal plain value
|
|
207
|
+
}
|
|
208
|
+
value = fns[i++](value);
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// Iterate a many() array, threading each element. A resumable `step` stays
|
|
213
|
+
// synchronous until one element returns a promise (a backpressure push, or
|
|
214
|
+
// genuine async); then it suspends AT that element and resumes the remainder
|
|
215
|
+
// via .then(step). Allocating one closure per actual suspension — not one per
|
|
216
|
+
// element — keeps live allocation O(1) in the array length even when the
|
|
217
|
+
// consumer backpressures from element 0 (the bug a per-element .then chain hit:
|
|
218
|
+
// a chunk-sized many() exploded into O(N) live promises). Mirrors nextGen.
|
|
219
|
+
const nextMany = (values, fns, i, push) => {
|
|
220
|
+
const step = j => {
|
|
221
|
+
for (; j < values.length; ++j) {
|
|
222
|
+
const r = next(values[j], fns, i, push);
|
|
223
|
+
if (r && typeof r.then == 'function') {
|
|
224
|
+
const jj = j;
|
|
225
|
+
return r.then(() => step(jj + 1));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
return step(0);
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// Iterate a generator, threading each yield. A resumable `step` keeps a sync
|
|
233
|
+
// generator with a draining queue fully synchronous; it goes async only when
|
|
234
|
+
// next() returns a promise (async generator) or a yield's push backpressures —
|
|
235
|
+
// then resumes via .then(step).
|
|
236
|
+
const nextGen = (it, fns, i, push) => {
|
|
237
|
+
const step = () => {
|
|
238
|
+
for (;;) {
|
|
239
|
+
let data = it.next();
|
|
240
|
+
if (data && typeof data.then == 'function') {
|
|
241
|
+
return data.then(d => {
|
|
242
|
+
if (d.done) return;
|
|
243
|
+
const r = next(d.value, fns, i, push);
|
|
244
|
+
return r && typeof r.then == 'function' ? r.then(step) : step();
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
if (data.done) return;
|
|
248
|
+
const r = next(data.value, fns, i, push);
|
|
249
|
+
if (r && typeof r.then == 'function') return r.then(step);
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
// Abnormal termination — a downstream stage threw (sync or rejected promise),
|
|
253
|
+
// or a push rejected (the gen bridge's consumer CANCEL) — leaves the source
|
|
254
|
+
// generator suspended at a yield, so its `finally {}` never runs and a
|
|
255
|
+
// resource-owning source (e.g. asyncBlockReader's FileHandle) leaks. Run
|
|
256
|
+
// `it.return()` to fire that finally, awaiting it for an async generator, then
|
|
257
|
+
// re-throw the ORIGINAL error. Normal completion (`data.done`) already ran the
|
|
258
|
+
// generator's own finally — don't touch it. The sync fast path stays
|
|
259
|
+
// overhead-free: a plain `try` plus one `.then(undefined, abort)` only when
|
|
260
|
+
// iteration actually suspended.
|
|
261
|
+
const abort = err => {
|
|
262
|
+
// If the source generator's own cleanup (its `finally`, fired by
|
|
263
|
+
// `it.return()`) ALSO fails, keep both errors instead of dropping the
|
|
264
|
+
// cleanup one. Combine only when `err` is a real Error — a non-Error
|
|
265
|
+
// control sentinel (e.g. gen()'s CANCEL on consumer break) must keep its
|
|
266
|
+
// identity so callers comparing against it still work.
|
|
267
|
+
const onCleanupError = cleanupErr =>
|
|
268
|
+
err instanceof Error
|
|
269
|
+
? new AggregateError([err, cleanupErr], 'pipeline error; generator cleanup also failed')
|
|
270
|
+
: err;
|
|
271
|
+
let ret;
|
|
272
|
+
try {
|
|
273
|
+
ret = it.return ? it.return() : undefined;
|
|
274
|
+
} catch (cleanupErr) {
|
|
275
|
+
throw onCleanupError(cleanupErr);
|
|
276
|
+
}
|
|
277
|
+
if (ret && typeof ret.then == 'function') {
|
|
278
|
+
return ret.then(
|
|
279
|
+
() => {
|
|
280
|
+
throw err;
|
|
281
|
+
},
|
|
282
|
+
cleanupErr => {
|
|
283
|
+
throw onCleanupError(cleanupErr);
|
|
284
|
+
}
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
throw err;
|
|
288
|
+
};
|
|
289
|
+
let r;
|
|
290
|
+
try {
|
|
291
|
+
r = step();
|
|
292
|
+
} catch (err) {
|
|
293
|
+
return abort(err);
|
|
294
|
+
}
|
|
295
|
+
return r && typeof r.then == 'function' ? r.then(undefined, abort) : r;
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
// Flush flushable stages (called when the factory's driver receives `none`).
|
|
299
|
+
// Mirrors fun.flush: each flushable's output threads through the stages after
|
|
300
|
+
// it, value-or-promise chained. Resumable `step` (same shape as nextMany) keeps
|
|
301
|
+
// live allocation O(1) in the number of flushable stages under backpressure.
|
|
302
|
+
const flush = (fns, index, push) => {
|
|
303
|
+
const step = i => {
|
|
304
|
+
for (; i < fns.length; ++i) {
|
|
305
|
+
const f = fns[i];
|
|
306
|
+
if (!isFlushable(f)) continue;
|
|
307
|
+
const r = next(f(none), fns, i + 1, push);
|
|
308
|
+
if (r && typeof r.then == 'function') {
|
|
309
|
+
const ii = i;
|
|
310
|
+
return r.then(() => step(ii + 1));
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
return step(index);
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
// @ts-self-types="./gen.d.ts"
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
// gen() builds a push→pull async-generator bridge over the shared executor
|
|
321
|
+
// (exec.next / exec.flush) — ~45% faster than the recursive `async function*` it
|
|
322
|
+
// replaced, whose native `yield*` delegation instantiated a nested generator per
|
|
323
|
+
// many() element. See [[projects/stream-chain/design/sync-when-possible-executor]].
|
|
324
|
+
const gen = (...fns) => {
|
|
325
|
+
fns = fns
|
|
326
|
+
.filter(fn => fn)
|
|
327
|
+
.flat(Infinity)
|
|
328
|
+
.map(fn => (isFunctionList(fn) ? getFunctionList(fn) : fn))
|
|
329
|
+
.flat(Infinity);
|
|
330
|
+
if (!fns.length) {
|
|
331
|
+
fns = [x => x];
|
|
332
|
+
}
|
|
333
|
+
let flushed = false;
|
|
334
|
+
|
|
335
|
+
// push→pull bridge: the shared executor drives the producer (exec.next, or
|
|
336
|
+
// exec.flush on `none`); each push parks on a promise the consumer resolves
|
|
337
|
+
// when it pulls the next value, so production stays one item ahead (bounded).
|
|
338
|
+
// A for-await `break` runs .return() → the finally rejects the parked push
|
|
339
|
+
// with CANCEL, unwinding exec; the driver swallows it (no leaked producer).
|
|
340
|
+
let g = async function* (value) {
|
|
341
|
+
if (flushed) throw Error('Call to a flushed pipe.');
|
|
342
|
+
const isFlush = value === none;
|
|
343
|
+
if (isFlush) flushed = true;
|
|
344
|
+
|
|
345
|
+
const pending = [];
|
|
346
|
+
/** @type {((value?: any) => void) | null} */
|
|
347
|
+
let wakeConsumer = null;
|
|
348
|
+
/** @type {((value?: any) => void) | null} */
|
|
349
|
+
let resolveProducer = null;
|
|
350
|
+
/** @type {((reason?: any) => void) | null} */
|
|
351
|
+
let rejectProducer = null;
|
|
352
|
+
let done = false,
|
|
353
|
+
error = null,
|
|
354
|
+
cancelled = false;
|
|
355
|
+
const CANCEL = Symbol('cancel');
|
|
356
|
+
|
|
357
|
+
const push = v => {
|
|
358
|
+
if (cancelled) throw CANCEL;
|
|
359
|
+
pending.push(v);
|
|
360
|
+
if (wakeConsumer) {
|
|
361
|
+
const w = wakeConsumer;
|
|
362
|
+
wakeConsumer = null;
|
|
363
|
+
w();
|
|
364
|
+
}
|
|
365
|
+
return new Promise((res, rej) => {
|
|
366
|
+
resolveProducer = res;
|
|
367
|
+
rejectProducer = rej;
|
|
368
|
+
});
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
Promise.resolve()
|
|
372
|
+
.then(() => (isFlush ? flush(fns, 0, push) : next(value, fns, 0, push)))
|
|
373
|
+
.then(
|
|
374
|
+
() => {},
|
|
375
|
+
e => {
|
|
376
|
+
if (e !== CANCEL) error = e;
|
|
377
|
+
}
|
|
378
|
+
)
|
|
379
|
+
.finally(() => {
|
|
380
|
+
done = true;
|
|
381
|
+
if (wakeConsumer) {
|
|
382
|
+
const w = wakeConsumer;
|
|
383
|
+
wakeConsumer = null;
|
|
384
|
+
w();
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
try {
|
|
389
|
+
for (;;) {
|
|
390
|
+
while (pending.length) {
|
|
391
|
+
const v = pending.shift();
|
|
392
|
+
if (resolveProducer) {
|
|
393
|
+
const r = resolveProducer;
|
|
394
|
+
resolveProducer = rejectProducer = null;
|
|
395
|
+
r();
|
|
396
|
+
}
|
|
397
|
+
yield v;
|
|
398
|
+
}
|
|
399
|
+
if (error) throw error;
|
|
400
|
+
if (done) return;
|
|
401
|
+
await new Promise(res => (wakeConsumer = res));
|
|
402
|
+
}
|
|
403
|
+
} finally {
|
|
404
|
+
cancelled = true;
|
|
405
|
+
if (rejectProducer) {
|
|
406
|
+
const rj = rejectProducer;
|
|
407
|
+
resolveProducer = rejectProducer = null;
|
|
408
|
+
rj(CANCEL);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
};
|
|
7
412
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
var src = {exports: {}};
|
|
13
|
-
|
|
14
|
-
const require$2 = createRequire(import.meta.url);
|
|
15
|
-
function __require$1() { return require$2("node:stream"); }
|
|
16
|
-
|
|
17
|
-
var defs = {};
|
|
18
|
-
|
|
19
|
-
var hasRequiredDefs;
|
|
20
|
-
|
|
21
|
-
function requireDefs () {
|
|
22
|
-
if (hasRequiredDefs) return defs;
|
|
23
|
-
hasRequiredDefs = 1;
|
|
24
|
-
|
|
25
|
-
const none = Symbol.for('object-stream.none');
|
|
26
|
-
const stop = Symbol.for('object-stream.stop');
|
|
27
|
-
|
|
28
|
-
const finalSymbol = Symbol.for('object-stream.final');
|
|
29
|
-
const manySymbol = Symbol.for('object-stream.many');
|
|
30
|
-
const flushSymbol = Symbol.for('object-stream.flush');
|
|
31
|
-
const fListSymbol = Symbol.for('object-stream.fList');
|
|
32
|
-
|
|
33
|
-
const finalValue = value => ({[finalSymbol]: 1, value});
|
|
34
|
-
const many = values => ({[manySymbol]: 1, values});
|
|
35
|
-
|
|
36
|
-
const isFinalValue = o => o && o[finalSymbol] === 1;
|
|
37
|
-
const isMany = o => o && o[manySymbol] === 1;
|
|
38
|
-
const isFlushable = o => o && o[flushSymbol] === 1;
|
|
39
|
-
const isFunctionList = o => o && o[fListSymbol] === 1;
|
|
40
|
-
|
|
41
|
-
const getFinalValue = o => o.value;
|
|
42
|
-
const getManyValues = o => o.values;
|
|
43
|
-
const getFunctionList = o => o.fList;
|
|
44
|
-
|
|
45
|
-
const flushable = (write, final = null) => {
|
|
46
|
-
const fn = final ? value => (value === none ? final() : write(value)) : write;
|
|
47
|
-
fn[flushSymbol] = 1;
|
|
48
|
-
return fn;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const setFunctionList = (o, fns) => {
|
|
52
|
-
o.fList = fns;
|
|
53
|
-
o[fListSymbol] = 1;
|
|
54
|
-
return o;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const clearFunctionList = o => {
|
|
58
|
-
delete o.fList;
|
|
59
|
-
delete o[fListSymbol];
|
|
60
|
-
return o;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
class Stop extends Error {}
|
|
64
|
-
|
|
65
|
-
const toMany = value =>
|
|
66
|
-
value === none ? many([]) : value && value[manySymbol] === 1 ? value : many([value]);
|
|
67
|
-
|
|
68
|
-
const normalizeMany = o => {
|
|
69
|
-
if (o?.[manySymbol] === 1) {
|
|
70
|
-
switch (o.values.length) {
|
|
71
|
-
case 0:
|
|
72
|
-
return none;
|
|
73
|
-
case 1:
|
|
74
|
-
return o.values[0];
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
return o;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const combineMany = (...args) => {
|
|
81
|
-
const values = [];
|
|
82
|
-
for (let i = 0; i < args.length; ++i) {
|
|
83
|
-
const a = args[i];
|
|
84
|
-
if (a === none) continue;
|
|
85
|
-
if (a?.[manySymbol] === 1) {
|
|
86
|
-
values.push(...a.values);
|
|
87
|
-
} else {
|
|
88
|
-
values.push(a);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return many(values);
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const combineManyMut = (a, ...args) => {
|
|
95
|
-
const values = a === none ? [] : a?.[manySymbol] === 1 ? a.values : [a];
|
|
96
|
-
for (let i = 0; i < args.length; ++i) {
|
|
97
|
-
const b = args[i];
|
|
98
|
-
if (b === none) continue;
|
|
99
|
-
if (b?.[manySymbol] === 1) {
|
|
100
|
-
values.push(...b.values);
|
|
101
|
-
} else {
|
|
102
|
-
values.push(b);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return many(values);
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
// old aliases
|
|
109
|
-
const final = finalValue;
|
|
110
|
-
|
|
111
|
-
defs.none = none;
|
|
112
|
-
defs.stop = stop;
|
|
113
|
-
defs.Stop = Stop;
|
|
114
|
-
|
|
115
|
-
defs.finalSymbol = finalSymbol;
|
|
116
|
-
defs.finalValue = finalValue;
|
|
117
|
-
defs.final = final;
|
|
118
|
-
defs.isFinalValue = isFinalValue;
|
|
119
|
-
defs.getFinalValue = getFinalValue;
|
|
120
|
-
|
|
121
|
-
defs.manySymbol = manySymbol;
|
|
122
|
-
defs.many = many;
|
|
123
|
-
defs.isMany = isMany;
|
|
124
|
-
defs.getManyValues = getManyValues;
|
|
125
|
-
|
|
126
|
-
defs.flushSymbol = flushSymbol;
|
|
127
|
-
defs.flushable = flushable;
|
|
128
|
-
defs.isFlushable = isFlushable;
|
|
129
|
-
|
|
130
|
-
defs.fListSymbol = fListSymbol;
|
|
131
|
-
defs.isFunctionList = isFunctionList;
|
|
132
|
-
defs.getFunctionList = getFunctionList;
|
|
133
|
-
defs.setFunctionList = setFunctionList;
|
|
134
|
-
defs.clearFunctionList = clearFunctionList;
|
|
135
|
-
|
|
136
|
-
defs.toMany = toMany;
|
|
137
|
-
defs.normalizeMany = normalizeMany;
|
|
138
|
-
defs.combineMany = combineMany;
|
|
139
|
-
defs.combineManyMut = combineManyMut;
|
|
140
|
-
return defs;
|
|
141
|
-
}
|
|
413
|
+
const needToFlush = fns.some(fn => isFlushable(fn));
|
|
414
|
+
if (needToFlush) g = flushable(g);
|
|
415
|
+
return setFunctionList(g, fns);
|
|
416
|
+
};
|
|
142
417
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
var hasRequiredGen;
|
|
146
|
-
|
|
147
|
-
function requireGen () {
|
|
148
|
-
if (hasRequiredGen) return gen.exports;
|
|
149
|
-
hasRequiredGen = 1;
|
|
150
|
-
|
|
151
|
-
const defs = requireDefs();
|
|
152
|
-
|
|
153
|
-
const next = async function* (value, fns, index) {
|
|
154
|
-
for (let i = index; i <= fns.length; ++i) {
|
|
155
|
-
if (value && typeof value.then == 'function') {
|
|
156
|
-
// thenable
|
|
157
|
-
value = await value;
|
|
158
|
-
}
|
|
159
|
-
if (value === defs.none) break;
|
|
160
|
-
if (value === defs.stop) throw new defs.Stop();
|
|
161
|
-
if (defs.isFinalValue(value)) {
|
|
162
|
-
yield defs.getFinalValue(value);
|
|
163
|
-
break;
|
|
164
|
-
}
|
|
165
|
-
if (defs.isMany(value)) {
|
|
166
|
-
const values = defs.getManyValues(value);
|
|
167
|
-
if (i == fns.length) {
|
|
168
|
-
yield* values;
|
|
169
|
-
} else {
|
|
170
|
-
for (let j = 0; j < values.length; ++j) {
|
|
171
|
-
yield* next(values[j], fns, i);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
break;
|
|
175
|
-
}
|
|
176
|
-
if (value && typeof value.next == 'function') {
|
|
177
|
-
// generator
|
|
178
|
-
for (;;) {
|
|
179
|
-
let data = value.next();
|
|
180
|
-
if (data && typeof data.then == 'function') {
|
|
181
|
-
data = await data;
|
|
182
|
-
}
|
|
183
|
-
if (data.done) break;
|
|
184
|
-
if (i == fns.length) {
|
|
185
|
-
yield data.value;
|
|
186
|
-
} else {
|
|
187
|
-
yield* next(data.value, fns, i);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
break;
|
|
191
|
-
}
|
|
192
|
-
if (i == fns.length) {
|
|
193
|
-
yield value;
|
|
194
|
-
break;
|
|
195
|
-
}
|
|
196
|
-
const f = fns[i];
|
|
197
|
-
value = f(value);
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
const gen$1 = (...fns) => {
|
|
202
|
-
fns = fns
|
|
203
|
-
.filter(fn => fn)
|
|
204
|
-
.flat(Infinity)
|
|
205
|
-
.map(fn => (defs.isFunctionList(fn) ? defs.getFunctionList(fn) : fn))
|
|
206
|
-
.flat(Infinity);
|
|
207
|
-
if (!fns.length) {
|
|
208
|
-
fns = [x => x];
|
|
209
|
-
}
|
|
210
|
-
let flushed = false;
|
|
211
|
-
let g = async function* (value) {
|
|
212
|
-
if (flushed) throw Error('Call to a flushed pipe.');
|
|
213
|
-
if (value !== defs.none) {
|
|
214
|
-
for (let i = 0; i <= fns.length; ++i) {
|
|
215
|
-
if (value && typeof value.then == 'function') {
|
|
216
|
-
yield* next(value, fns, i);
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
if (value === defs.none) return;
|
|
220
|
-
if (value === defs.stop) throw new defs.Stop();
|
|
221
|
-
if (defs.isFinalValue(value)) {
|
|
222
|
-
yield defs.getFinalValue(value);
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
if (defs.isMany(value) || (value && typeof value.next == 'function')) {
|
|
226
|
-
yield* next(value, fns, i);
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
if (i == fns.length) {
|
|
230
|
-
yield value;
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
value = fns[i](value);
|
|
234
|
-
}
|
|
235
|
-
} else {
|
|
236
|
-
flushed = true;
|
|
237
|
-
for (let i = 0; i < fns.length; ++i) {
|
|
238
|
-
const f = fns[i];
|
|
239
|
-
if (defs.isFlushable(f)) {
|
|
240
|
-
yield* next(f(defs.none), fns, i + 1);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
};
|
|
245
|
-
const needToFlush = fns.some(fn => defs.isFlushable(fn));
|
|
246
|
-
if (needToFlush) g = defs.flushable(g);
|
|
247
|
-
return defs.setFunctionList(g, fns);
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
gen.exports = gen$1;
|
|
251
|
-
|
|
252
|
-
gen.exports.next = next;
|
|
253
|
-
return gen.exports;
|
|
254
|
-
}
|
|
418
|
+
// @ts-self-types="./asStream.d.ts"
|
|
255
419
|
|
|
256
|
-
var asStream_1;
|
|
257
|
-
var hasRequiredAsStream;
|
|
258
|
-
|
|
259
|
-
function requireAsStream () {
|
|
260
|
-
if (hasRequiredAsStream) return asStream_1;
|
|
261
|
-
hasRequiredAsStream = 1;
|
|
262
|
-
|
|
263
|
-
const {Duplex} = __require$1();
|
|
264
|
-
const defs = requireDefs();
|
|
265
|
-
|
|
266
|
-
const asStream = (fn, options) => {
|
|
267
|
-
if (typeof fn != 'function') throw TypeError('Only a function is accepted as the first argument');
|
|
268
|
-
|
|
269
|
-
// pump variables
|
|
270
|
-
let paused = Promise.resolve(),
|
|
271
|
-
resolvePaused = null;
|
|
272
|
-
const queue = [];
|
|
273
|
-
|
|
274
|
-
// pause/resume
|
|
275
|
-
const resume = () => {
|
|
276
|
-
if (!resolvePaused) return;
|
|
277
|
-
resolvePaused();
|
|
278
|
-
resolvePaused = null;
|
|
279
|
-
paused = Promise.resolve();
|
|
280
|
-
};
|
|
281
|
-
const pause = () => {
|
|
282
|
-
if (resolvePaused) return;
|
|
283
|
-
paused = new Promise(resolve => (resolvePaused = resolve));
|
|
284
|
-
};
|
|
285
|
-
|
|
286
|
-
const innerFns = defs.isFunctionList(fn) ? fn.fList : null;
|
|
287
|
-
|
|
288
|
-
const applyFns = innerFns
|
|
289
|
-
? function apply(value, i, push) {
|
|
290
|
-
for (;;) {
|
|
291
|
-
if (value && typeof value.then == 'function') return value.then(v => apply(v, i, push));
|
|
292
|
-
if (value === undefined || value === null || value === defs.none) return;
|
|
293
|
-
if (value === defs.stop) throw new defs.Stop();
|
|
294
|
-
if (defs.isFinalValue(value)) {
|
|
295
|
-
push(defs.getFinalValue(value));
|
|
296
|
-
return;
|
|
297
|
-
}
|
|
298
|
-
if (defs.isMany(value)) {
|
|
299
|
-
const values = defs.getManyValues(value);
|
|
300
|
-
if (i >= innerFns.length) {
|
|
301
|
-
for (let j = 0; j < values.length; ++j) push(values[j]);
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
let pending;
|
|
305
|
-
for (let j = 0; j < values.length; ++j) {
|
|
306
|
-
if (pending) {
|
|
307
|
-
const jj = j;
|
|
308
|
-
pending = pending.then(() => apply(values[jj], i, push));
|
|
309
|
-
} else {
|
|
310
|
-
const result = apply(values[j], i, push);
|
|
311
|
-
if (result) pending = result;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
return pending;
|
|
315
|
-
}
|
|
316
|
-
if (value && typeof value.next == 'function') {
|
|
317
|
-
return (async () => {
|
|
318
|
-
for (;;) {
|
|
319
|
-
let data = value.next();
|
|
320
|
-
if (data && typeof data.then == 'function') data = await data;
|
|
321
|
-
if (data.done) break;
|
|
322
|
-
const result = apply(data.value, i, push);
|
|
323
|
-
if (result) await result;
|
|
324
|
-
}
|
|
325
|
-
})();
|
|
326
|
-
}
|
|
327
|
-
if (i >= innerFns.length) {
|
|
328
|
-
push(value);
|
|
329
|
-
return;
|
|
330
|
-
}
|
|
331
|
-
value = innerFns[i++](value);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
: null;
|
|
335
|
-
|
|
336
|
-
let stopped = false;
|
|
337
|
-
let stream = null; // will be assigned later
|
|
338
|
-
|
|
339
|
-
// data processing
|
|
340
|
-
const pushResults = values => {
|
|
341
|
-
if (values && typeof values.next == 'function') {
|
|
342
|
-
// generator
|
|
343
|
-
queue.push(values);
|
|
344
|
-
return;
|
|
345
|
-
}
|
|
346
|
-
// array
|
|
347
|
-
queue.push(values[Symbol.iterator]());
|
|
348
|
-
};
|
|
349
|
-
const pump = async () => {
|
|
350
|
-
while (queue.length) {
|
|
351
|
-
await paused;
|
|
352
|
-
const gen = queue[queue.length - 1];
|
|
353
|
-
let result = gen.next();
|
|
354
|
-
if (result && typeof result.then == 'function') {
|
|
355
|
-
result = await result;
|
|
356
|
-
}
|
|
357
|
-
if (result.done) {
|
|
358
|
-
queue.pop();
|
|
359
|
-
continue;
|
|
360
|
-
}
|
|
361
|
-
let value = result.value;
|
|
362
|
-
if (value && typeof value.then == 'function') {
|
|
363
|
-
value = await value;
|
|
364
|
-
}
|
|
365
|
-
await sanitize(value);
|
|
366
|
-
}
|
|
367
|
-
};
|
|
368
|
-
const sanitize = async value => {
|
|
369
|
-
if (value === undefined || value === null || value === defs.none) return;
|
|
370
|
-
if (value === defs.stop) throw new defs.Stop();
|
|
371
|
-
|
|
372
|
-
if (defs.isMany(value)) {
|
|
373
|
-
pushResults(defs.getManyValues(value));
|
|
374
|
-
return pump();
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
if (defs.isFinalValue(value)) {
|
|
378
|
-
// a final value is not supported, it is treated as a regular value
|
|
379
|
-
value = defs.getFinalValue(value);
|
|
380
|
-
return processValue(value);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
if (!stream.push(value)) {
|
|
384
|
-
pause();
|
|
385
|
-
}
|
|
386
|
-
};
|
|
387
|
-
const processChunk = async (chunk, encoding) => {
|
|
388
|
-
try {
|
|
389
|
-
const value = fn(chunk, encoding);
|
|
390
|
-
await processValue(value);
|
|
391
|
-
} catch (error) {
|
|
392
|
-
if (error instanceof defs.Stop) {
|
|
393
|
-
stream.push(null);
|
|
394
|
-
stopped = true;
|
|
395
|
-
return;
|
|
396
|
-
}
|
|
397
|
-
throw error;
|
|
398
|
-
}
|
|
399
|
-
};
|
|
400
|
-
const processValue = async value => {
|
|
401
|
-
if (value && typeof value.then == 'function') {
|
|
402
|
-
// thenable
|
|
403
|
-
return value.then(value => processValue(value));
|
|
404
|
-
}
|
|
405
|
-
if (value && typeof value.next == 'function') {
|
|
406
|
-
// generator
|
|
407
|
-
pushResults(value);
|
|
408
|
-
return pump();
|
|
409
|
-
}
|
|
410
|
-
return sanitize(value);
|
|
411
|
-
};
|
|
412
|
-
|
|
413
|
-
stream = new Duplex({
|
|
414
|
-
writableObjectMode: true,
|
|
415
|
-
readableObjectMode: true,
|
|
416
|
-
...options,
|
|
417
|
-
write(chunk, encoding, callback) {
|
|
418
|
-
if (stopped) {
|
|
419
|
-
callback(null);
|
|
420
|
-
return;
|
|
421
|
-
}
|
|
422
|
-
// fast path for gen() compositions: process inner functions directly
|
|
423
|
-
if (applyFns) {
|
|
424
|
-
let backpressure = false;
|
|
425
|
-
let asyncResult;
|
|
426
|
-
try {
|
|
427
|
-
asyncResult = applyFns(chunk, 0, value => {
|
|
428
|
-
if (!stream.push(value)) backpressure = true;
|
|
429
|
-
});
|
|
430
|
-
} catch (error) {
|
|
431
|
-
if (error instanceof defs.Stop) {
|
|
432
|
-
stream.push(null);
|
|
433
|
-
stopped = true;
|
|
434
|
-
callback(null);
|
|
435
|
-
return;
|
|
436
|
-
}
|
|
437
|
-
callback(error);
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
|
-
if (asyncResult) {
|
|
441
|
-
asyncResult.then(
|
|
442
|
-
() => callback(null),
|
|
443
|
-
error => {
|
|
444
|
-
if (error instanceof defs.Stop) {
|
|
445
|
-
stream.push(null);
|
|
446
|
-
stopped = true;
|
|
447
|
-
callback(null);
|
|
448
|
-
return;
|
|
449
|
-
}
|
|
450
|
-
callback(error);
|
|
451
|
-
}
|
|
452
|
-
);
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
455
|
-
if (backpressure) {
|
|
456
|
-
pause();
|
|
457
|
-
paused.then(() => callback(null));
|
|
458
|
-
} else {
|
|
459
|
-
callback(null);
|
|
460
|
-
}
|
|
461
|
-
return;
|
|
462
|
-
}
|
|
463
|
-
let value;
|
|
464
|
-
try {
|
|
465
|
-
value = fn(chunk, encoding);
|
|
466
|
-
} catch (error) {
|
|
467
|
-
if (error instanceof defs.Stop) {
|
|
468
|
-
stream.push(null);
|
|
469
|
-
stopped = true;
|
|
470
|
-
callback(null);
|
|
471
|
-
return;
|
|
472
|
-
}
|
|
473
|
-
callback(error);
|
|
474
|
-
return;
|
|
475
|
-
}
|
|
476
|
-
// sync fast path: plain value (not a promise, generator, or special)
|
|
477
|
-
if (
|
|
478
|
-
!(value && (typeof value.then == 'function' || typeof value.next == 'function')) &&
|
|
479
|
-
value !== defs.stop &&
|
|
480
|
-
!defs.isMany(value) &&
|
|
481
|
-
!defs.isFinalValue(value)
|
|
482
|
-
) {
|
|
483
|
-
if (value !== undefined && value !== null && value !== defs.none) {
|
|
484
|
-
if (!stream.push(value)) {
|
|
485
|
-
pause();
|
|
486
|
-
paused.then(() => callback(null));
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
callback(null);
|
|
491
|
-
return;
|
|
492
|
-
}
|
|
493
|
-
// async slow path: promises, generators, many, finalValue, stop
|
|
494
|
-
processValue(value).then(
|
|
495
|
-
() => callback(null),
|
|
496
|
-
error => {
|
|
497
|
-
if (error instanceof defs.Stop) {
|
|
498
|
-
stream.push(null);
|
|
499
|
-
stopped = true;
|
|
500
|
-
callback(null);
|
|
501
|
-
return;
|
|
502
|
-
}
|
|
503
|
-
callback(error);
|
|
504
|
-
}
|
|
505
|
-
);
|
|
506
|
-
},
|
|
507
|
-
final(callback) {
|
|
508
|
-
// fast path for gen() compositions: flush inner functions directly
|
|
509
|
-
if (applyFns) {
|
|
510
|
-
let backpressure = false;
|
|
511
|
-
let asyncChain;
|
|
512
|
-
try {
|
|
513
|
-
const pushFn = value => {
|
|
514
|
-
if (!stream.push(value)) backpressure = true;
|
|
515
|
-
};
|
|
516
|
-
for (let i = 0; i < innerFns.length; ++i) {
|
|
517
|
-
if (defs.isFlushable(innerFns[i])) {
|
|
518
|
-
if (asyncChain) {
|
|
519
|
-
const ii = i;
|
|
520
|
-
asyncChain = asyncChain.then(() =>
|
|
521
|
-
applyFns(innerFns[ii](defs.none), ii + 1, pushFn)
|
|
522
|
-
);
|
|
523
|
-
} else {
|
|
524
|
-
const result = applyFns(innerFns[i](defs.none), i + 1, pushFn);
|
|
525
|
-
if (result) asyncChain = result;
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
} catch (error) {
|
|
530
|
-
if (error instanceof defs.Stop) {
|
|
531
|
-
stream.push(null);
|
|
532
|
-
stopped = true;
|
|
533
|
-
callback(null);
|
|
534
|
-
return;
|
|
535
|
-
}
|
|
536
|
-
callback(error);
|
|
537
|
-
return;
|
|
538
|
-
}
|
|
539
|
-
if (asyncChain) {
|
|
540
|
-
asyncChain.then(
|
|
541
|
-
() => (stream.push(null), callback(null)),
|
|
542
|
-
error => {
|
|
543
|
-
if (error instanceof defs.Stop) {
|
|
544
|
-
stopped = true;
|
|
545
|
-
stream.push(null);
|
|
546
|
-
callback(null);
|
|
547
|
-
return;
|
|
548
|
-
}
|
|
549
|
-
callback(error);
|
|
550
|
-
}
|
|
551
|
-
);
|
|
552
|
-
return;
|
|
553
|
-
}
|
|
554
|
-
stream.push(null);
|
|
555
|
-
if (backpressure) {
|
|
556
|
-
pause();
|
|
557
|
-
paused.then(() => callback(null));
|
|
558
|
-
} else {
|
|
559
|
-
callback(null);
|
|
560
|
-
}
|
|
561
|
-
return;
|
|
562
|
-
}
|
|
563
|
-
if (!defs.isFlushable(fn)) {
|
|
564
|
-
stream.push(null);
|
|
565
|
-
callback(null);
|
|
566
|
-
return;
|
|
567
|
-
}
|
|
568
|
-
processChunk(defs.none, null).then(
|
|
569
|
-
() => {
|
|
570
|
-
if (!stopped) stream.push(null);
|
|
571
|
-
callback(null);
|
|
572
|
-
},
|
|
573
|
-
error => callback(error)
|
|
574
|
-
);
|
|
575
|
-
},
|
|
576
|
-
read() {
|
|
577
|
-
resume();
|
|
578
|
-
}
|
|
579
|
-
});
|
|
580
|
-
|
|
581
|
-
return stream;
|
|
582
|
-
};
|
|
583
|
-
|
|
584
|
-
asStream_1 = asStream;
|
|
585
|
-
return asStream_1;
|
|
586
|
-
}
|
|
587
420
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
function
|
|
591
|
-
|
|
592
|
-
hasRequiredSrc$1 = 1;
|
|
593
|
-
|
|
594
|
-
const {Readable, Writable, Duplex} = __require$1();
|
|
595
|
-
const defs = requireDefs();
|
|
596
|
-
const gen = requireGen();
|
|
597
|
-
const asStream = requireAsStream();
|
|
598
|
-
|
|
599
|
-
// is*NodeStream functions taken from https://github.com/nodejs/node/blob/master/lib/internal/streams/utils.js
|
|
600
|
-
const isReadableNodeStream = obj =>
|
|
601
|
-
obj &&
|
|
602
|
-
typeof obj.pipe === 'function' &&
|
|
603
|
-
typeof obj.on === 'function' &&
|
|
604
|
-
(!obj._writableState ||
|
|
605
|
-
(typeof obj._readableState === 'object' ? obj._readableState.readable : null) !== false) && // Duplex
|
|
606
|
-
(!obj._writableState || obj._readableState); // Writable has .pipe.
|
|
607
|
-
|
|
608
|
-
const isWritableNodeStream = obj =>
|
|
609
|
-
obj &&
|
|
610
|
-
typeof obj.write === 'function' &&
|
|
611
|
-
typeof obj.on === 'function' &&
|
|
612
|
-
(!obj._readableState ||
|
|
613
|
-
(typeof obj._writableState === 'object' ? obj._writableState.writable : null) !== false); // Duplex
|
|
614
|
-
|
|
615
|
-
const isDuplexNodeStream = obj =>
|
|
616
|
-
obj &&
|
|
617
|
-
typeof obj.pipe === 'function' &&
|
|
618
|
-
obj._readableState &&
|
|
619
|
-
typeof obj.on === 'function' &&
|
|
620
|
-
typeof obj.write === 'function';
|
|
621
|
-
|
|
622
|
-
const isNodeStream = obj => {
|
|
623
|
-
return (
|
|
624
|
-
obj &&
|
|
625
|
-
(obj._readableState ||
|
|
626
|
-
obj._writableState ||
|
|
627
|
-
(typeof obj.write === 'function' && typeof obj.on === 'function') ||
|
|
628
|
-
(typeof obj.pipe === 'function' && typeof obj.on === 'function'))
|
|
629
|
-
);
|
|
630
|
-
};
|
|
631
|
-
|
|
632
|
-
const isReadableWebStream = obj =>
|
|
633
|
-
!!(
|
|
634
|
-
obj &&
|
|
635
|
-
!isNodeStream(obj) &&
|
|
636
|
-
typeof obj.pipeThrough === 'function' &&
|
|
637
|
-
typeof obj.getReader === 'function' &&
|
|
638
|
-
typeof obj.cancel === 'function'
|
|
639
|
-
);
|
|
640
|
-
|
|
641
|
-
const isWritableWebStream = obj =>
|
|
642
|
-
!!(
|
|
643
|
-
obj &&
|
|
644
|
-
!isNodeStream(obj) &&
|
|
645
|
-
typeof obj.getWriter === 'function' &&
|
|
646
|
-
typeof obj.abort === 'function'
|
|
647
|
-
);
|
|
648
|
-
|
|
649
|
-
const isDuplexWebStream = obj =>
|
|
650
|
-
!!(
|
|
651
|
-
obj &&
|
|
652
|
-
!isNodeStream(obj) &&
|
|
653
|
-
typeof obj.readable === 'object' &&
|
|
654
|
-
typeof obj.writable === 'object'
|
|
655
|
-
);
|
|
656
|
-
|
|
657
|
-
const groupFunctions = (output, fn, index, fns) => {
|
|
658
|
-
if (
|
|
659
|
-
isDuplexNodeStream(fn) ||
|
|
660
|
-
(!index && isReadableNodeStream(fn)) ||
|
|
661
|
-
(index === fns.length - 1 && isWritableNodeStream(fn))
|
|
662
|
-
) {
|
|
663
|
-
output.push(fn);
|
|
664
|
-
return output;
|
|
665
|
-
}
|
|
666
|
-
if (isDuplexWebStream(fn)) {
|
|
667
|
-
output.push(Duplex.fromWeb(fn, {objectMode: true}));
|
|
668
|
-
return output;
|
|
669
|
-
}
|
|
670
|
-
if (!index && isReadableWebStream(fn)) {
|
|
671
|
-
output.push(Readable.fromWeb(fn, {objectMode: true}));
|
|
672
|
-
return output;
|
|
673
|
-
}
|
|
674
|
-
if (index === fns.length - 1 && isWritableWebStream(fn)) {
|
|
675
|
-
output.push(Writable.fromWeb(fn, {objectMode: true}));
|
|
676
|
-
return output;
|
|
677
|
-
}
|
|
678
|
-
if (typeof fn != 'function')
|
|
679
|
-
throw TypeError('Item #' + index + ' is not a proper stream, nor a function.');
|
|
680
|
-
if (!output.length) output.push([]);
|
|
681
|
-
const last = output[output.length - 1];
|
|
682
|
-
if (Array.isArray(last)) {
|
|
683
|
-
last.push(fn);
|
|
684
|
-
} else {
|
|
685
|
-
output.push([fn]);
|
|
686
|
-
}
|
|
687
|
-
return output;
|
|
688
|
-
};
|
|
689
|
-
|
|
690
|
-
const produceStreams = item => {
|
|
691
|
-
if (Array.isArray(item)) {
|
|
692
|
-
if (!item.length) return null;
|
|
693
|
-
if (item.length == 1) return item[0] && chain.asStream(item[0]);
|
|
694
|
-
return chain.asStream(chain.gen(...item));
|
|
695
|
-
}
|
|
696
|
-
return item;
|
|
697
|
-
};
|
|
698
|
-
|
|
699
|
-
const wrapFunctions = (fn, index, fns) => {
|
|
700
|
-
if (
|
|
701
|
-
isDuplexNodeStream(fn) ||
|
|
702
|
-
(!index && isReadableNodeStream(fn)) ||
|
|
703
|
-
(index === fns.length - 1 && isWritableNodeStream(fn))
|
|
704
|
-
) {
|
|
705
|
-
return fn; // an acceptable stream
|
|
706
|
-
}
|
|
707
|
-
if (isDuplexWebStream(fn)) {
|
|
708
|
-
return Duplex.fromWeb(fn, {objectMode: true});
|
|
709
|
-
}
|
|
710
|
-
if (!index && isReadableWebStream(fn)) {
|
|
711
|
-
return Readable.fromWeb(fn, {objectMode: true});
|
|
712
|
-
}
|
|
713
|
-
if (index === fns.length - 1 && isWritableWebStream(fn)) {
|
|
714
|
-
return Writable.fromWeb(fn, {objectMode: true});
|
|
715
|
-
}
|
|
716
|
-
if (typeof fn == 'function') return chain.asStream(fn); // a function
|
|
717
|
-
throw TypeError('Item #' + index + ' is not a proper stream, nor a function.');
|
|
718
|
-
};
|
|
719
|
-
|
|
720
|
-
// default implementation of required stream methods
|
|
721
|
-
|
|
722
|
-
const write = (input, chunk, encoding, callback) => {
|
|
723
|
-
let error = null;
|
|
724
|
-
try {
|
|
725
|
-
input.write(chunk, encoding, e => callback(e || error));
|
|
726
|
-
} catch (e) {
|
|
727
|
-
error = e;
|
|
728
|
-
}
|
|
729
|
-
};
|
|
730
|
-
|
|
731
|
-
const final = (input, callback) => {
|
|
732
|
-
let error = null;
|
|
733
|
-
try {
|
|
734
|
-
input.end(null, null, e => callback(e || error));
|
|
735
|
-
} catch (e) {
|
|
736
|
-
error = e;
|
|
737
|
-
}
|
|
738
|
-
};
|
|
739
|
-
|
|
740
|
-
const read = output => {
|
|
741
|
-
output.resume();
|
|
742
|
-
};
|
|
743
|
-
|
|
744
|
-
// the chain creator
|
|
745
|
-
|
|
746
|
-
const chain = (fns, options) => {
|
|
747
|
-
if (!Array.isArray(fns) || !fns.length) {
|
|
748
|
-
throw TypeError("Chain's first argument should be a non-empty array.");
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
fns = fns.flat(Infinity).filter(fn => fn);
|
|
752
|
-
|
|
753
|
-
const streams = (
|
|
754
|
-
options && options.noGrouping
|
|
755
|
-
? fns.map(wrapFunctions)
|
|
756
|
-
: fns
|
|
757
|
-
.map(fn => (defs.isFunctionList(fn) ? defs.getFunctionList(fn) : fn))
|
|
758
|
-
.flat(Infinity)
|
|
759
|
-
.reduce(groupFunctions, [])
|
|
760
|
-
.map(produceStreams)
|
|
761
|
-
).filter(s => s),
|
|
762
|
-
input = streams[0],
|
|
763
|
-
output = streams.reduce((output, item) => (output && output.pipe(item)) || item);
|
|
764
|
-
|
|
765
|
-
let stream = null; // will be assigned later
|
|
766
|
-
|
|
767
|
-
let writeMethod = (chunk, encoding, callback) => write(input, chunk, encoding, callback),
|
|
768
|
-
finalMethod = callback => final(input, callback),
|
|
769
|
-
readMethod = () => read(output);
|
|
770
|
-
|
|
771
|
-
if (!isWritableNodeStream(input)) {
|
|
772
|
-
writeMethod = (_1, _2, callback) => callback(null);
|
|
773
|
-
finalMethod = callback => callback(null);
|
|
774
|
-
input.on('end', () => stream.end());
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
if (isReadableNodeStream(output)) {
|
|
778
|
-
output.on('data', chunk => !stream.push(chunk) && output.pause());
|
|
779
|
-
output.on('end', () => stream.push(null));
|
|
780
|
-
} else {
|
|
781
|
-
readMethod = () => {}; // nop
|
|
782
|
-
output.on('finish', () => stream.push(null));
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
stream = new Duplex({
|
|
786
|
-
writableObjectMode: true,
|
|
787
|
-
readableObjectMode: true,
|
|
788
|
-
...options,
|
|
789
|
-
readable: isReadableNodeStream(output),
|
|
790
|
-
writable: isWritableNodeStream(input),
|
|
791
|
-
write: writeMethod,
|
|
792
|
-
final: finalMethod,
|
|
793
|
-
read: readMethod
|
|
794
|
-
});
|
|
795
|
-
stream.streams = streams;
|
|
796
|
-
stream.input = input;
|
|
797
|
-
stream.output = output;
|
|
798
|
-
|
|
799
|
-
if (!isReadableNodeStream(output)) {
|
|
800
|
-
stream.resume();
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
// connect events
|
|
804
|
-
if (!options || !options.skipEvents) {
|
|
805
|
-
streams.forEach(item => item.on('error', error => stream.emit('error', error)));
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
return stream;
|
|
809
|
-
};
|
|
810
|
-
|
|
811
|
-
const dataSource = fn => {
|
|
812
|
-
if (typeof fn == 'function') return fn;
|
|
813
|
-
if (fn) {
|
|
814
|
-
if (typeof fn[Symbol.asyncIterator] == 'function') return fn[Symbol.asyncIterator].bind(fn);
|
|
815
|
-
if (typeof fn[Symbol.iterator] == 'function') return fn[Symbol.iterator].bind(fn);
|
|
816
|
-
}
|
|
817
|
-
throw new TypeError('The argument should be a function or an iterable object.');
|
|
818
|
-
};
|
|
819
|
-
|
|
820
|
-
src.exports = chain;
|
|
821
|
-
|
|
822
|
-
// from defs.js
|
|
823
|
-
src.exports.none = defs.none;
|
|
824
|
-
src.exports.stop = defs.stop;
|
|
825
|
-
src.exports.Stop = defs.Stop;
|
|
826
|
-
|
|
827
|
-
src.exports.finalSymbol = defs.finalSymbol;
|
|
828
|
-
src.exports.finalValue = defs.finalValue;
|
|
829
|
-
src.exports.final = defs.final;
|
|
830
|
-
src.exports.isFinalValue = defs.isFinalValue;
|
|
831
|
-
src.exports.getFinalValue = defs.getFinalValue;
|
|
832
|
-
|
|
833
|
-
src.exports.manySymbol = defs.manySymbol;
|
|
834
|
-
src.exports.many = defs.many;
|
|
835
|
-
src.exports.isMany = defs.isMany;
|
|
836
|
-
src.exports.getManyValues = defs.getManyValues;
|
|
837
|
-
|
|
838
|
-
src.exports.flushSymbol = defs.flushSymbol;
|
|
839
|
-
src.exports.flushable = defs.flushable;
|
|
840
|
-
src.exports.isFlushable = defs.isFlushable;
|
|
841
|
-
|
|
842
|
-
src.exports.fListSymbol = defs.fListSymbol;
|
|
843
|
-
src.exports.isFunctionList = defs.isFunctionList;
|
|
844
|
-
src.exports.getFunctionList = defs.getFunctionList;
|
|
845
|
-
src.exports.setFunctionList = defs.setFunctionList;
|
|
846
|
-
src.exports.clearFunctionList = defs.clearFunctionList;
|
|
847
|
-
|
|
848
|
-
src.exports.toMany = defs.toMany;
|
|
849
|
-
src.exports.normalizeMany = defs.normalizeMany;
|
|
850
|
-
src.exports.combineMany = defs.combineMany;
|
|
851
|
-
src.exports.combineManyMut = defs.combineManyMut;
|
|
852
|
-
|
|
853
|
-
src.exports.chain = chain; // for compatibility with 2.x
|
|
854
|
-
src.exports.chainUnchecked = chain; // for TypeScript to bypass type checks
|
|
855
|
-
src.exports.gen = gen;
|
|
856
|
-
src.exports.asStream = asStream;
|
|
857
|
-
|
|
858
|
-
src.exports.dataSource = dataSource;
|
|
859
|
-
return src.exports;
|
|
860
|
-
}
|
|
421
|
+
const asStream = (fn, options) => {
|
|
422
|
+
if (typeof fn != 'function') {
|
|
423
|
+
throw TypeError('Only a function is accepted as the first argument');
|
|
424
|
+
}
|
|
861
425
|
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
426
|
+
const innerFns = isFunctionList(fn) ? fn.fList : null;
|
|
427
|
+
|
|
428
|
+
let stopped = false;
|
|
429
|
+
let nullPushed = false;
|
|
430
|
+
let resolvePaused = null;
|
|
431
|
+
let stream = null;
|
|
432
|
+
|
|
433
|
+
const resume = () => {
|
|
434
|
+
if (!resolvePaused) return;
|
|
435
|
+
const resolve = resolvePaused;
|
|
436
|
+
resolvePaused = null;
|
|
437
|
+
resolve();
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
// Idempotent: prevents 'error' from push-after-end on duplicate end signals.
|
|
441
|
+
const signalEnd = () => {
|
|
442
|
+
if (nullPushed) return;
|
|
443
|
+
nullPushed = true;
|
|
444
|
+
stream.push(null);
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
// After Stop / destroy, enqueue silently no-ops so producers see clean
|
|
448
|
+
// completion instead of push-after-end errors.
|
|
449
|
+
const enqueue = value => {
|
|
450
|
+
if (stopped) return;
|
|
451
|
+
if (!stream.push(value)) {
|
|
452
|
+
return new Promise(resolve => {
|
|
453
|
+
resolvePaused = resolve;
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
// Slow-path generator queue (preserves iterator state across re-entry) —
|
|
459
|
+
// used by the single-fn processValue path below.
|
|
460
|
+
const queue = [];
|
|
461
|
+
|
|
462
|
+
const pump = async () => {
|
|
463
|
+
while (queue.length) {
|
|
464
|
+
const g = queue[queue.length - 1];
|
|
465
|
+
let result = g.next();
|
|
466
|
+
if (result && typeof result.then == 'function') result = await result;
|
|
467
|
+
if (result.done) {
|
|
468
|
+
queue.pop();
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
let value = result.value;
|
|
472
|
+
if (value && typeof value.then == 'function') value = await value;
|
|
473
|
+
const r = processValue(value);
|
|
474
|
+
if (r) await r;
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
// Sync-when-possible single-fn path: returns undefined for plain
|
|
479
|
+
// non-backpressured paths, a Promise for promise unwrap / pump drain /
|
|
480
|
+
// backpressure await. Array-of-Many is iterated directly.
|
|
481
|
+
const processValue = value => {
|
|
482
|
+
if (value && typeof value.then == 'function') {
|
|
483
|
+
return value.then(processValue);
|
|
484
|
+
}
|
|
485
|
+
if (value == null || value === none) return;
|
|
486
|
+
if (value === stop) throw new Stop();
|
|
487
|
+
if (isMany(value)) {
|
|
488
|
+
const values = getManyValues(value);
|
|
489
|
+
let promise;
|
|
490
|
+
for (let i = 0; i < values.length; ++i) {
|
|
491
|
+
if (promise) {
|
|
492
|
+
const ii = i;
|
|
493
|
+
promise = promise.then(() => processValue(values[ii]));
|
|
494
|
+
} else {
|
|
495
|
+
const r = processValue(values[i]);
|
|
496
|
+
if (r) promise = r;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return promise;
|
|
500
|
+
}
|
|
501
|
+
if (isFinalValue(value)) {
|
|
502
|
+
return processValue(getFinalValue(value));
|
|
503
|
+
}
|
|
504
|
+
if (value && typeof value.next == 'function') {
|
|
505
|
+
queue.push(value);
|
|
506
|
+
return pump();
|
|
507
|
+
}
|
|
508
|
+
return enqueue(value);
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
const absorbStop = error => {
|
|
512
|
+
if (error instanceof Stop) {
|
|
513
|
+
stopped = true;
|
|
514
|
+
signalEnd();
|
|
515
|
+
return true;
|
|
516
|
+
}
|
|
517
|
+
return false;
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
const finishWrite = (callback, error) => {
|
|
521
|
+
if (!error) return callback(null);
|
|
522
|
+
if (absorbStop(error)) return callback(null);
|
|
523
|
+
callback(error);
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
stream = new Duplex({
|
|
527
|
+
writableObjectMode: true,
|
|
528
|
+
readableObjectMode: true,
|
|
529
|
+
...options,
|
|
530
|
+
write(chunk, encoding, callback) {
|
|
531
|
+
if (stopped) return callback(null);
|
|
532
|
+
if (innerFns) {
|
|
533
|
+
let r;
|
|
534
|
+
try {
|
|
535
|
+
r = next(chunk, innerFns, 0, enqueue);
|
|
536
|
+
} catch (error) {
|
|
537
|
+
return finishWrite(callback, error);
|
|
538
|
+
}
|
|
539
|
+
if (r && typeof r.then == 'function') {
|
|
540
|
+
r.then(
|
|
541
|
+
() => callback(null),
|
|
542
|
+
error => finishWrite(callback, error)
|
|
543
|
+
);
|
|
544
|
+
} else {
|
|
545
|
+
callback(null); // ran fully sync — no promise, no microtask
|
|
546
|
+
}
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
let r;
|
|
550
|
+
try {
|
|
551
|
+
r = processValue(fn(chunk, encoding));
|
|
552
|
+
} catch (error) {
|
|
553
|
+
return finishWrite(callback, error);
|
|
554
|
+
}
|
|
555
|
+
if (r) {
|
|
556
|
+
r.then(
|
|
557
|
+
() => callback(null),
|
|
558
|
+
error => finishWrite(callback, error)
|
|
559
|
+
);
|
|
560
|
+
} else {
|
|
561
|
+
callback(null);
|
|
562
|
+
}
|
|
563
|
+
},
|
|
564
|
+
final(callback) {
|
|
565
|
+
const onComplete = () => {
|
|
566
|
+
signalEnd();
|
|
567
|
+
callback(null);
|
|
568
|
+
};
|
|
569
|
+
if (innerFns) {
|
|
570
|
+
let r;
|
|
571
|
+
try {
|
|
572
|
+
r = flush(innerFns, 0, enqueue);
|
|
573
|
+
} catch (error) {
|
|
574
|
+
return finishWrite(callback, error);
|
|
575
|
+
}
|
|
576
|
+
if (r && typeof r.then == 'function') {
|
|
577
|
+
r.then(onComplete, error => finishWrite(callback, error));
|
|
578
|
+
} else {
|
|
579
|
+
onComplete();
|
|
580
|
+
}
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
if (!isFlushable(fn)) {
|
|
584
|
+
onComplete();
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
let r;
|
|
588
|
+
try {
|
|
589
|
+
r = processValue(fn(none, null));
|
|
590
|
+
} catch (error) {
|
|
591
|
+
return finishWrite(callback, error);
|
|
592
|
+
}
|
|
593
|
+
if (r) {
|
|
594
|
+
r.then(onComplete, error => finishWrite(callback, error));
|
|
595
|
+
} else {
|
|
596
|
+
onComplete();
|
|
597
|
+
}
|
|
598
|
+
},
|
|
599
|
+
read() {
|
|
600
|
+
resume();
|
|
601
|
+
},
|
|
602
|
+
// Unblock any pending paused-promise so an in-flight write can settle —
|
|
603
|
+
// mirrors asWebStream's controller.signal listener for writer.abort().
|
|
604
|
+
destroy(error, callback) {
|
|
605
|
+
stopped = true;
|
|
606
|
+
resume();
|
|
607
|
+
callback(error);
|
|
608
|
+
}
|
|
609
|
+
});
|
|
900
610
|
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
function requireParser () {
|
|
904
|
-
if (hasRequiredParser) return parser.exports;
|
|
905
|
-
hasRequiredParser = 1;
|
|
906
|
-
|
|
907
|
-
const {asStream, flushable, gen, many, none} = requireSrc$1();
|
|
908
|
-
const fixUtf8Stream = requireFixUtf8Stream();
|
|
909
|
-
|
|
910
|
-
const patterns = {
|
|
911
|
-
value1: /[\"\{\[\]\-\d]|true\b|false\b|null\b|\s{1,256}/y,
|
|
912
|
-
string: /[^\x00-\x1f\"\\]{1,256}|\\[bfnrt\"\\\/]|\\u[\da-fA-F]{4}|\"/y,
|
|
913
|
-
key1: /[\"\}]|\s{1,256}/y,
|
|
914
|
-
colon: /\:|\s{1,256}/y,
|
|
915
|
-
comma: /[\,\]\}]|\s{1,256}/y,
|
|
916
|
-
ws: /\s{1,256}/y,
|
|
917
|
-
numberStart: /\d/y,
|
|
918
|
-
numberDigit: /\d{0,256}/y,
|
|
919
|
-
numberFraction: /[\.eE]/y,
|
|
920
|
-
numberExponent: /[eE]/y,
|
|
921
|
-
numberExpSign: /[-+]/y
|
|
922
|
-
};
|
|
923
|
-
const MAX_PATTERN_SIZE = 16;
|
|
924
|
-
|
|
925
|
-
patterns.numberFracStart = patterns.numberExpStart = patterns.numberStart;
|
|
926
|
-
patterns.numberFracDigit = patterns.numberExpDigit = patterns.numberDigit;
|
|
927
|
-
|
|
928
|
-
const expected = {object: 'objectStop', array: 'arrayStop', '': 'done'};
|
|
929
|
-
|
|
930
|
-
const tokenStartObject = {name: 'startObject'},
|
|
931
|
-
tokenEndObject = {name: 'endObject'},
|
|
932
|
-
tokenStartArray = {name: 'startArray'},
|
|
933
|
-
tokenEndArray = {name: 'endArray'},
|
|
934
|
-
tokenStartString = {name: 'startString'},
|
|
935
|
-
tokenEndString = {name: 'endString'},
|
|
936
|
-
tokenStartNumber = {name: 'startNumber'},
|
|
937
|
-
tokenEndNumber = {name: 'endNumber'},
|
|
938
|
-
tokenStartKey = {name: 'startKey'},
|
|
939
|
-
tokenEndKey = {name: 'endKey'},
|
|
940
|
-
literalTokens = {
|
|
941
|
-
true: {name: 'trueValue', value: true},
|
|
942
|
-
false: {name: 'falseValue', value: false},
|
|
943
|
-
null: {name: 'nullValue', value: null}
|
|
944
|
-
};
|
|
945
|
-
|
|
946
|
-
// long hexadecimal codes: \uXXXX
|
|
947
|
-
const fromHex = s => String.fromCharCode(parseInt(s.slice(2), 16));
|
|
948
|
-
|
|
949
|
-
// short codes: \b \f \n \r \t \" \\ \/
|
|
950
|
-
const codes = {b: '\b', f: '\f', n: '\n', r: '\r', t: '\t', '"': '"', '\\': '\\', '/': '/'};
|
|
951
|
-
|
|
952
|
-
const jsonParser = options => {
|
|
953
|
-
let packKeys = true,
|
|
954
|
-
packStrings = true,
|
|
955
|
-
packNumbers = true,
|
|
956
|
-
streamKeys = true,
|
|
957
|
-
streamStrings = true,
|
|
958
|
-
streamNumbers = true,
|
|
959
|
-
jsonStreaming = false;
|
|
960
|
-
|
|
961
|
-
if (options) {
|
|
962
|
-
'packValues' in options && (packKeys = packStrings = packNumbers = options.packValues);
|
|
963
|
-
'packKeys' in options && (packKeys = options.packKeys);
|
|
964
|
-
'packStrings' in options && (packStrings = options.packStrings);
|
|
965
|
-
'packNumbers' in options && (packNumbers = options.packNumbers);
|
|
966
|
-
'streamValues' in options && (streamKeys = streamStrings = streamNumbers = options.streamValues);
|
|
967
|
-
'streamKeys' in options && (streamKeys = options.streamKeys);
|
|
968
|
-
'streamStrings' in options && (streamStrings = options.streamStrings);
|
|
969
|
-
'streamNumbers' in options && (streamNumbers = options.streamNumbers);
|
|
970
|
-
jsonStreaming = options.jsonStreaming;
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
!packKeys && (streamKeys = true);
|
|
974
|
-
!packStrings && (streamStrings = true);
|
|
975
|
-
!packNumbers && (streamNumbers = true);
|
|
976
|
-
|
|
977
|
-
let done = false,
|
|
978
|
-
expect = jsonStreaming ? 'done' : 'value',
|
|
979
|
-
parent = '',
|
|
980
|
-
openNumber = false,
|
|
981
|
-
accumulator = '',
|
|
982
|
-
buffer = '';
|
|
983
|
-
|
|
984
|
-
const stack = [];
|
|
985
|
-
|
|
986
|
-
return flushable(buf => {
|
|
987
|
-
const tokens = [];
|
|
988
|
-
|
|
989
|
-
if (buf === none) {
|
|
990
|
-
done = true;
|
|
991
|
-
} else {
|
|
992
|
-
buffer += buf;
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
let match,
|
|
996
|
-
value,
|
|
997
|
-
index = 0;
|
|
998
|
-
|
|
999
|
-
main: for (;;) {
|
|
1000
|
-
switch (expect) {
|
|
1001
|
-
case 'value1':
|
|
1002
|
-
case 'value':
|
|
1003
|
-
patterns.value1.lastIndex = index;
|
|
1004
|
-
match = patterns.value1.exec(buffer);
|
|
1005
|
-
if (!match) {
|
|
1006
|
-
if (done || index + MAX_PATTERN_SIZE < buffer.length) {
|
|
1007
|
-
if (index < buffer.length) throw new Error('Parser cannot parse input: expected a value');
|
|
1008
|
-
throw new Error('Parser has expected a value');
|
|
1009
|
-
}
|
|
1010
|
-
break main; // wait for more input
|
|
1011
|
-
}
|
|
1012
|
-
value = match[0];
|
|
1013
|
-
switch (value) {
|
|
1014
|
-
case '"':
|
|
1015
|
-
if (streamStrings) tokens.push(tokenStartString);
|
|
1016
|
-
expect = 'string';
|
|
1017
|
-
break;
|
|
1018
|
-
case '{':
|
|
1019
|
-
tokens.push(tokenStartObject);
|
|
1020
|
-
stack.push(parent);
|
|
1021
|
-
parent = 'object';
|
|
1022
|
-
expect = 'key1';
|
|
1023
|
-
break;
|
|
1024
|
-
case '[':
|
|
1025
|
-
tokens.push(tokenStartArray);
|
|
1026
|
-
stack.push(parent);
|
|
1027
|
-
parent = 'array';
|
|
1028
|
-
expect = 'value1';
|
|
1029
|
-
break;
|
|
1030
|
-
case ']':
|
|
1031
|
-
if (expect !== 'value1') throw new Error("Parser cannot parse input: unexpected token ']'");
|
|
1032
|
-
if (openNumber) {
|
|
1033
|
-
if (streamNumbers) tokens.push(tokenEndNumber);
|
|
1034
|
-
openNumber = false;
|
|
1035
|
-
if (packNumbers) {
|
|
1036
|
-
tokens.push({name: 'numberValue', value: accumulator});
|
|
1037
|
-
accumulator = '';
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
tokens.push(tokenEndArray);
|
|
1041
|
-
parent = stack.pop();
|
|
1042
|
-
expect = expected[parent];
|
|
1043
|
-
break;
|
|
1044
|
-
case '-':
|
|
1045
|
-
openNumber = true;
|
|
1046
|
-
if (streamNumbers) {
|
|
1047
|
-
tokens.push(tokenStartNumber, {name: 'numberChunk', value: '-'});
|
|
1048
|
-
}
|
|
1049
|
-
packNumbers && (accumulator = '-');
|
|
1050
|
-
expect = 'numberStart';
|
|
1051
|
-
break;
|
|
1052
|
-
case '0':
|
|
1053
|
-
openNumber = true;
|
|
1054
|
-
if (streamNumbers) {
|
|
1055
|
-
tokens.push(tokenStartNumber, {name: 'numberChunk', value: '0'});
|
|
1056
|
-
}
|
|
1057
|
-
packNumbers && (accumulator = '0');
|
|
1058
|
-
expect = 'numberFraction';
|
|
1059
|
-
break;
|
|
1060
|
-
case '1':
|
|
1061
|
-
case '2':
|
|
1062
|
-
case '3':
|
|
1063
|
-
case '4':
|
|
1064
|
-
case '5':
|
|
1065
|
-
case '6':
|
|
1066
|
-
case '7':
|
|
1067
|
-
case '8':
|
|
1068
|
-
case '9':
|
|
1069
|
-
openNumber = true;
|
|
1070
|
-
if (streamNumbers) {
|
|
1071
|
-
tokens.push(tokenStartNumber, {name: 'numberChunk', value});
|
|
1072
|
-
}
|
|
1073
|
-
packNumbers && (accumulator = value);
|
|
1074
|
-
expect = 'numberDigit';
|
|
1075
|
-
break;
|
|
1076
|
-
case 'true':
|
|
1077
|
-
case 'false':
|
|
1078
|
-
case 'null':
|
|
1079
|
-
if (buffer.length - index === value.length && !done) break main; // wait for more input
|
|
1080
|
-
tokens.push(literalTokens[value]);
|
|
1081
|
-
expect = expected[parent];
|
|
1082
|
-
break;
|
|
1083
|
-
// default: // ws
|
|
1084
|
-
}
|
|
1085
|
-
index += value.length;
|
|
1086
|
-
break;
|
|
1087
|
-
case 'keyVal':
|
|
1088
|
-
case 'string':
|
|
1089
|
-
patterns.string.lastIndex = index;
|
|
1090
|
-
match = patterns.string.exec(buffer);
|
|
1091
|
-
if (!match) {
|
|
1092
|
-
if (index < buffer.length && (done || buffer.length - index >= 6)) throw new Error('Parser cannot parse input: escaped characters');
|
|
1093
|
-
if (done) throw new Error('Parser has expected a string value');
|
|
1094
|
-
break main; // wait for more input
|
|
1095
|
-
}
|
|
1096
|
-
value = match[0];
|
|
1097
|
-
if (value === '"') {
|
|
1098
|
-
if (expect === 'keyVal') {
|
|
1099
|
-
if (streamKeys) tokens.push(tokenEndKey);
|
|
1100
|
-
if (packKeys) {
|
|
1101
|
-
tokens.push({name: 'keyValue', value: accumulator});
|
|
1102
|
-
accumulator = '';
|
|
1103
|
-
}
|
|
1104
|
-
expect = 'colon';
|
|
1105
|
-
} else {
|
|
1106
|
-
if (streamStrings) tokens.push(tokenEndString);
|
|
1107
|
-
if (packStrings) {
|
|
1108
|
-
tokens.push({name: 'stringValue', value: accumulator});
|
|
1109
|
-
accumulator = '';
|
|
1110
|
-
}
|
|
1111
|
-
expect = expected[parent];
|
|
1112
|
-
}
|
|
1113
|
-
} else if (value.length > 1 && value.charAt(0) === '\\') {
|
|
1114
|
-
const t = value.length == 2 ? codes[value.charAt(1)] : fromHex(value);
|
|
1115
|
-
if (expect === 'keyVal' ? streamKeys : streamStrings) {
|
|
1116
|
-
tokens.push({name: 'stringChunk', value: t});
|
|
1117
|
-
}
|
|
1118
|
-
if (expect === 'keyVal' ? packKeys : packStrings) {
|
|
1119
|
-
accumulator += t;
|
|
1120
|
-
}
|
|
1121
|
-
} else {
|
|
1122
|
-
if (expect === 'keyVal' ? streamKeys : streamStrings) {
|
|
1123
|
-
tokens.push({name: 'stringChunk', value});
|
|
1124
|
-
}
|
|
1125
|
-
if (expect === 'keyVal' ? packKeys : packStrings) {
|
|
1126
|
-
accumulator += value;
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
index += value.length;
|
|
1130
|
-
break;
|
|
1131
|
-
case 'key1':
|
|
1132
|
-
case 'key':
|
|
1133
|
-
patterns.key1.lastIndex = index;
|
|
1134
|
-
match = patterns.key1.exec(buffer);
|
|
1135
|
-
if (!match) {
|
|
1136
|
-
if (index < buffer.length || done) throw new Error('Parser cannot parse input: expected an object key');
|
|
1137
|
-
break main; // wait for more input
|
|
1138
|
-
}
|
|
1139
|
-
value = match[0];
|
|
1140
|
-
if (value === '"') {
|
|
1141
|
-
if (streamKeys) tokens.push(tokenStartKey);
|
|
1142
|
-
expect = 'keyVal';
|
|
1143
|
-
} else if (value === '}') {
|
|
1144
|
-
if (expect !== 'key1') throw new Error("Parser cannot parse input: unexpected token '}'");
|
|
1145
|
-
tokens.push(tokenEndObject);
|
|
1146
|
-
parent = stack.pop();
|
|
1147
|
-
expect = expected[parent];
|
|
1148
|
-
}
|
|
1149
|
-
index += value.length;
|
|
1150
|
-
break;
|
|
1151
|
-
case 'colon':
|
|
1152
|
-
patterns.colon.lastIndex = index;
|
|
1153
|
-
match = patterns.colon.exec(buffer);
|
|
1154
|
-
if (!match) {
|
|
1155
|
-
if (index < buffer.length || done) throw new Error("Parser cannot parse input: expected ':'");
|
|
1156
|
-
break main; // wait for more input
|
|
1157
|
-
}
|
|
1158
|
-
value = match[0];
|
|
1159
|
-
value === ':' && (expect = 'value');
|
|
1160
|
-
index += value.length;
|
|
1161
|
-
break;
|
|
1162
|
-
case 'arrayStop':
|
|
1163
|
-
case 'objectStop':
|
|
1164
|
-
patterns.comma.lastIndex = index;
|
|
1165
|
-
match = patterns.comma.exec(buffer);
|
|
1166
|
-
if (!match) {
|
|
1167
|
-
if (index < buffer.length || done) throw new Error("Parser cannot parse input: expected ','");
|
|
1168
|
-
break main; // wait for more input
|
|
1169
|
-
}
|
|
1170
|
-
if (openNumber) {
|
|
1171
|
-
if (streamNumbers) tokens.push(tokenEndNumber);
|
|
1172
|
-
openNumber = false;
|
|
1173
|
-
if (packNumbers) {
|
|
1174
|
-
tokens.push({name: 'numberValue', value: accumulator});
|
|
1175
|
-
accumulator = '';
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
value = match[0];
|
|
1179
|
-
if (value === ',') {
|
|
1180
|
-
expect = expect === 'arrayStop' ? 'value' : 'key';
|
|
1181
|
-
} else if (value === '}' || value === ']') {
|
|
1182
|
-
if (value === '}' ? expect === 'arrayStop' : expect !== 'arrayStop') {
|
|
1183
|
-
throw new Error("Parser cannot parse input: expected '" + (expect === 'arrayStop' ? ']' : '}') + "'");
|
|
1184
|
-
}
|
|
1185
|
-
tokens.push(value === '}' ? tokenEndObject : tokenEndArray);
|
|
1186
|
-
parent = stack.pop();
|
|
1187
|
-
expect = expected[parent];
|
|
1188
|
-
}
|
|
1189
|
-
index += value.length;
|
|
1190
|
-
break;
|
|
1191
|
-
// number chunks
|
|
1192
|
-
case 'numberStart': // [0-9]
|
|
1193
|
-
patterns.numberStart.lastIndex = index;
|
|
1194
|
-
match = patterns.numberStart.exec(buffer);
|
|
1195
|
-
if (!match) {
|
|
1196
|
-
if (index < buffer.length || done) throw new Error('Parser cannot parse input: expected a starting digit');
|
|
1197
|
-
break main; // wait for more input
|
|
1198
|
-
}
|
|
1199
|
-
value = match[0];
|
|
1200
|
-
if (streamNumbers) tokens.push({name: 'numberChunk', value});
|
|
1201
|
-
packNumbers && (accumulator += value);
|
|
1202
|
-
expect = value === '0' ? 'numberFraction' : 'numberDigit';
|
|
1203
|
-
index += value.length;
|
|
1204
|
-
break;
|
|
1205
|
-
case 'numberDigit': // [0-9]*
|
|
1206
|
-
patterns.numberDigit.lastIndex = index;
|
|
1207
|
-
match = patterns.numberDigit.exec(buffer);
|
|
1208
|
-
if (!match) {
|
|
1209
|
-
if (index < buffer.length || done) throw new Error('Parser cannot parse input: expected a digit');
|
|
1210
|
-
break main; // wait for more input
|
|
1211
|
-
}
|
|
1212
|
-
value = match[0];
|
|
1213
|
-
if (value) {
|
|
1214
|
-
if (streamNumbers) tokens.push({name: 'numberChunk', value});
|
|
1215
|
-
packNumbers && (accumulator += value);
|
|
1216
|
-
index += value.length;
|
|
1217
|
-
} else {
|
|
1218
|
-
if (index < buffer.length) {
|
|
1219
|
-
expect = 'numberFraction';
|
|
1220
|
-
break;
|
|
1221
|
-
}
|
|
1222
|
-
if (done) {
|
|
1223
|
-
expect = expected[parent];
|
|
1224
|
-
break;
|
|
1225
|
-
}
|
|
1226
|
-
break main; // wait for more input
|
|
1227
|
-
}
|
|
1228
|
-
break;
|
|
1229
|
-
case 'numberFraction': // [\.eE]?
|
|
1230
|
-
patterns.numberFraction.lastIndex = index;
|
|
1231
|
-
match = patterns.numberFraction.exec(buffer);
|
|
1232
|
-
if (!match) {
|
|
1233
|
-
if (index < buffer.length || done) {
|
|
1234
|
-
expect = expected[parent];
|
|
1235
|
-
break;
|
|
1236
|
-
}
|
|
1237
|
-
break main; // wait for more input
|
|
1238
|
-
}
|
|
1239
|
-
value = match[0];
|
|
1240
|
-
if (streamNumbers) tokens.push({name: 'numberChunk', value});
|
|
1241
|
-
packNumbers && (accumulator += value);
|
|
1242
|
-
expect = value === '.' ? 'numberFracStart' : 'numberExpSign';
|
|
1243
|
-
index += value.length;
|
|
1244
|
-
break;
|
|
1245
|
-
case 'numberFracStart': // [0-9]
|
|
1246
|
-
patterns.numberFracStart.lastIndex = index;
|
|
1247
|
-
match = patterns.numberFracStart.exec(buffer);
|
|
1248
|
-
if (!match) {
|
|
1249
|
-
if (index < buffer.length || done) throw new Error('Parser cannot parse input: expected a fractional part of a number');
|
|
1250
|
-
break main; // wait for more input
|
|
1251
|
-
}
|
|
1252
|
-
value = match[0];
|
|
1253
|
-
if (streamNumbers) tokens.push({name: 'numberChunk', value});
|
|
1254
|
-
packNumbers && (accumulator += value);
|
|
1255
|
-
expect = 'numberFracDigit';
|
|
1256
|
-
index += value.length;
|
|
1257
|
-
break;
|
|
1258
|
-
case 'numberFracDigit': // [0-9]*
|
|
1259
|
-
patterns.numberFracDigit.lastIndex = index;
|
|
1260
|
-
match = patterns.numberFracDigit.exec(buffer);
|
|
1261
|
-
value = match[0];
|
|
1262
|
-
if (value) {
|
|
1263
|
-
if (streamNumbers) tokens.push({name: 'numberChunk', value});
|
|
1264
|
-
packNumbers && (accumulator += value);
|
|
1265
|
-
index += value.length;
|
|
1266
|
-
} else {
|
|
1267
|
-
if (index < buffer.length) {
|
|
1268
|
-
expect = 'numberExponent';
|
|
1269
|
-
break;
|
|
1270
|
-
}
|
|
1271
|
-
if (done) {
|
|
1272
|
-
expect = expected[parent];
|
|
1273
|
-
break;
|
|
1274
|
-
}
|
|
1275
|
-
break main; // wait for more input
|
|
1276
|
-
}
|
|
1277
|
-
break;
|
|
1278
|
-
case 'numberExponent': // [eE]?
|
|
1279
|
-
patterns.numberExponent.lastIndex = index;
|
|
1280
|
-
match = patterns.numberExponent.exec(buffer);
|
|
1281
|
-
if (!match) {
|
|
1282
|
-
if (index < buffer.length) {
|
|
1283
|
-
expect = expected[parent];
|
|
1284
|
-
break;
|
|
1285
|
-
}
|
|
1286
|
-
if (done) {
|
|
1287
|
-
expect = expected[parent];
|
|
1288
|
-
break;
|
|
1289
|
-
}
|
|
1290
|
-
break main; // wait for more input
|
|
1291
|
-
}
|
|
1292
|
-
value = match[0];
|
|
1293
|
-
if (streamNumbers) tokens.push({name: 'numberChunk', value});
|
|
1294
|
-
packNumbers && (accumulator += value);
|
|
1295
|
-
expect = 'numberExpSign';
|
|
1296
|
-
index += value.length;
|
|
1297
|
-
break;
|
|
1298
|
-
case 'numberExpSign': // [-+]?
|
|
1299
|
-
patterns.numberExpSign.lastIndex = index;
|
|
1300
|
-
match = patterns.numberExpSign.exec(buffer);
|
|
1301
|
-
if (!match) {
|
|
1302
|
-
if (index < buffer.length) {
|
|
1303
|
-
expect = 'numberExpStart';
|
|
1304
|
-
break;
|
|
1305
|
-
}
|
|
1306
|
-
if (done) throw new Error('Parser has expected an exponent value of a number');
|
|
1307
|
-
break main; // wait for more input
|
|
1308
|
-
}
|
|
1309
|
-
value = match[0];
|
|
1310
|
-
if (streamNumbers) tokens.push({name: 'numberChunk', value});
|
|
1311
|
-
packNumbers && (accumulator += value);
|
|
1312
|
-
expect = 'numberExpStart';
|
|
1313
|
-
index += value.length;
|
|
1314
|
-
break;
|
|
1315
|
-
case 'numberExpStart': // [0-9]
|
|
1316
|
-
patterns.numberExpStart.lastIndex = index;
|
|
1317
|
-
match = patterns.numberExpStart.exec(buffer);
|
|
1318
|
-
if (!match) {
|
|
1319
|
-
if (index < buffer.length || done) throw new Error('Parser cannot parse input: expected an exponent part of a number');
|
|
1320
|
-
break main; // wait for more input
|
|
1321
|
-
}
|
|
1322
|
-
value = match[0];
|
|
1323
|
-
if (streamNumbers) tokens.push({name: 'numberChunk', value});
|
|
1324
|
-
packNumbers && (accumulator += value);
|
|
1325
|
-
expect = 'numberExpDigit';
|
|
1326
|
-
index += value.length;
|
|
1327
|
-
break;
|
|
1328
|
-
case 'numberExpDigit': // [0-9]*
|
|
1329
|
-
patterns.numberExpDigit.lastIndex = index;
|
|
1330
|
-
match = patterns.numberExpDigit.exec(buffer);
|
|
1331
|
-
value = match[0];
|
|
1332
|
-
if (value) {
|
|
1333
|
-
if (streamNumbers) tokens.push({name: 'numberChunk', value});
|
|
1334
|
-
packNumbers && (accumulator += value);
|
|
1335
|
-
index += value.length;
|
|
1336
|
-
} else {
|
|
1337
|
-
if (index < buffer.length || done) {
|
|
1338
|
-
expect = expected[parent];
|
|
1339
|
-
break;
|
|
1340
|
-
}
|
|
1341
|
-
break main; // wait for more input
|
|
1342
|
-
}
|
|
1343
|
-
break;
|
|
1344
|
-
case 'done':
|
|
1345
|
-
patterns.ws.lastIndex = index;
|
|
1346
|
-
match = patterns.ws.exec(buffer);
|
|
1347
|
-
if (!match) {
|
|
1348
|
-
if (index < buffer.length) {
|
|
1349
|
-
if (jsonStreaming) {
|
|
1350
|
-
if (openNumber) {
|
|
1351
|
-
if (streamNumbers) tokens.push(tokenEndNumber);
|
|
1352
|
-
openNumber = false;
|
|
1353
|
-
if (packNumbers) {
|
|
1354
|
-
tokens.push({name: 'numberValue', value: accumulator});
|
|
1355
|
-
accumulator = '';
|
|
1356
|
-
}
|
|
1357
|
-
}
|
|
1358
|
-
expect = 'value';
|
|
1359
|
-
break;
|
|
1360
|
-
}
|
|
1361
|
-
throw new Error('Parser cannot parse input: unexpected characters');
|
|
1362
|
-
}
|
|
1363
|
-
break main; // wait for more input
|
|
1364
|
-
}
|
|
1365
|
-
value = match[0];
|
|
1366
|
-
if (openNumber) {
|
|
1367
|
-
if (streamNumbers) tokens.push(tokenEndNumber);
|
|
1368
|
-
openNumber = false;
|
|
1369
|
-
if (packNumbers) {
|
|
1370
|
-
tokens.push({name: 'numberValue', value: accumulator});
|
|
1371
|
-
accumulator = '';
|
|
1372
|
-
}
|
|
1373
|
-
}
|
|
1374
|
-
index += value.length;
|
|
1375
|
-
break;
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
|
-
if (done && openNumber) {
|
|
1379
|
-
if (streamNumbers) tokens.push(tokenEndNumber);
|
|
1380
|
-
openNumber = false;
|
|
1381
|
-
if (packNumbers) {
|
|
1382
|
-
tokens.push({name: 'numberValue', value: accumulator});
|
|
1383
|
-
accumulator = '';
|
|
1384
|
-
}
|
|
1385
|
-
}
|
|
1386
|
-
buffer = buffer.slice(index);
|
|
1387
|
-
return tokens.length ? many(tokens) : none;
|
|
1388
|
-
});
|
|
1389
|
-
};
|
|
1390
|
-
|
|
1391
|
-
const parser$1 = options => gen(fixUtf8Stream(), jsonParser(options));
|
|
1392
|
-
|
|
1393
|
-
parser$1.asStream = options => asStream(parser$1(options), options);
|
|
1394
|
-
|
|
1395
|
-
parser.exports = parser$1;
|
|
1396
|
-
parser.exports.parser = parser$1; // for backward compatibility with 1.x
|
|
1397
|
-
return parser.exports;
|
|
1398
|
-
}
|
|
611
|
+
return stream;
|
|
612
|
+
};
|
|
1399
613
|
|
|
1400
|
-
|
|
1401
|
-
var hasRequiredEmit;
|
|
614
|
+
// @ts-self-types="./asWebStream.d.ts"
|
|
1402
615
|
|
|
1403
|
-
function requireEmit () {
|
|
1404
|
-
if (hasRequiredEmit) return emit_1;
|
|
1405
|
-
hasRequiredEmit = 1;
|
|
1406
616
|
|
|
1407
|
-
|
|
617
|
+
const asWebStream = (fn, options) => {
|
|
618
|
+
if (isDuplexWebStream$1(fn) || isReadableWebStream$1(fn) || isWritableWebStream$1(fn)) {
|
|
619
|
+
return fn;
|
|
620
|
+
}
|
|
621
|
+
if (typeof fn !== 'function') {
|
|
622
|
+
throw new TypeError('Only a function or Web Streams object is accepted as the first argument');
|
|
623
|
+
}
|
|
1408
624
|
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
625
|
+
// Web Streams' standard `QueuingStrategy` shape ({highWaterMark, size}).
|
|
626
|
+
// `strategy` is shorthand for "apply to both sides"; per-side wins.
|
|
627
|
+
const strategy = options?.strategy;
|
|
628
|
+
const readableStrategy = options?.readableStrategy ?? strategy;
|
|
629
|
+
const writableStrategy = options?.writableStrategy ?? strategy;
|
|
630
|
+
|
|
631
|
+
const innerFns = isFunctionList(fn) ? fn.fList : null;
|
|
632
|
+
|
|
633
|
+
let stopped = false;
|
|
634
|
+
let readableClosed = false;
|
|
635
|
+
let writableErrored = false;
|
|
636
|
+
let readableController;
|
|
637
|
+
let writableController;
|
|
638
|
+
let pendingDrain = null;
|
|
639
|
+
|
|
640
|
+
const unblockDrain = () => {
|
|
641
|
+
if (!pendingDrain) return;
|
|
642
|
+
const resolve = pendingDrain;
|
|
643
|
+
pendingDrain = null;
|
|
644
|
+
resolve();
|
|
645
|
+
};
|
|
646
|
+
|
|
647
|
+
// Idempotent: cancel() marks `readableClosed` because the consumer side
|
|
648
|
+
// auto-closes the controller (re-calling close() would throw).
|
|
649
|
+
const closeReadable = () => {
|
|
650
|
+
if (readableClosed) return;
|
|
651
|
+
readableClosed = true;
|
|
652
|
+
readableController.close();
|
|
653
|
+
};
|
|
654
|
+
const errorReadable = reason => {
|
|
655
|
+
if (readableClosed) return;
|
|
656
|
+
readableClosed = true;
|
|
657
|
+
readableController.error(reason);
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
// Mirror TransformStream: cancel on the readable side propagates to the
|
|
661
|
+
// writable as an error so the producer learns the consumer gave up.
|
|
662
|
+
const errorWritable = reason => {
|
|
663
|
+
if (writableErrored || !writableController) return;
|
|
664
|
+
writableErrored = true;
|
|
665
|
+
writableController.error(reason);
|
|
666
|
+
};
|
|
667
|
+
|
|
668
|
+
const readable = new ReadableStream(
|
|
669
|
+
{
|
|
670
|
+
start(c) {
|
|
671
|
+
readableController = c;
|
|
672
|
+
},
|
|
673
|
+
pull() {
|
|
674
|
+
unblockDrain();
|
|
675
|
+
},
|
|
676
|
+
cancel(reason) {
|
|
677
|
+
stopped = true;
|
|
678
|
+
readableClosed = true;
|
|
679
|
+
unblockDrain();
|
|
680
|
+
errorWritable(reason);
|
|
681
|
+
}
|
|
682
|
+
},
|
|
683
|
+
readableStrategy
|
|
684
|
+
);
|
|
685
|
+
|
|
686
|
+
// After cancel/abort, enqueue silently no-ops so producers see clean
|
|
687
|
+
// completion instead of TypeError from enqueue-on-closed-controller.
|
|
688
|
+
const enqueue = value => {
|
|
689
|
+
if (stopped) return;
|
|
690
|
+
readableController.enqueue(value);
|
|
691
|
+
if (readableController.desiredSize <= 0) {
|
|
692
|
+
return new Promise(resolve => {
|
|
693
|
+
pendingDrain = resolve;
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
|
|
698
|
+
// Slow-path generator queue (preserves iterator state across re-entry) —
|
|
699
|
+
// used by the single-fn processValue path below.
|
|
700
|
+
const queue = [];
|
|
701
|
+
|
|
702
|
+
const pump = async () => {
|
|
703
|
+
while (queue.length) {
|
|
704
|
+
const g = queue[queue.length - 1];
|
|
705
|
+
let result = g.next();
|
|
706
|
+
if (result && typeof result.then == 'function') result = await result;
|
|
707
|
+
if (result.done) {
|
|
708
|
+
queue.pop();
|
|
709
|
+
continue;
|
|
710
|
+
}
|
|
711
|
+
let value = result.value;
|
|
712
|
+
if (value && typeof value.then == 'function') value = await value;
|
|
713
|
+
const r = processValue(value);
|
|
714
|
+
if (r) await r;
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
|
|
718
|
+
// Sync-when-possible: returns undefined for plain non-backpressured paths,
|
|
719
|
+
// returns a Promise for promise unwrap / pump drain / backpressure await.
|
|
720
|
+
// Array-of-Many is iterated directly — no iterator allocation per Many.
|
|
721
|
+
const processValue = value => {
|
|
722
|
+
if (value && typeof value.then == 'function') {
|
|
723
|
+
return value.then(processValue);
|
|
724
|
+
}
|
|
725
|
+
if (value == null || value === none) return;
|
|
726
|
+
if (value === stop) throw new Stop();
|
|
727
|
+
if (isMany(value)) {
|
|
728
|
+
const values = getManyValues(value);
|
|
729
|
+
let promise;
|
|
730
|
+
for (let i = 0; i < values.length; ++i) {
|
|
731
|
+
if (promise) {
|
|
732
|
+
const ii = i;
|
|
733
|
+
promise = promise.then(() => processValue(values[ii]));
|
|
734
|
+
} else {
|
|
735
|
+
const r = processValue(values[i]);
|
|
736
|
+
if (r) promise = r;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
return promise;
|
|
740
|
+
}
|
|
741
|
+
if (isFinalValue(value)) {
|
|
742
|
+
return processValue(getFinalValue(value));
|
|
743
|
+
}
|
|
744
|
+
if (value && typeof value.next == 'function') {
|
|
745
|
+
queue.push(value);
|
|
746
|
+
return pump();
|
|
747
|
+
}
|
|
748
|
+
return enqueue(value);
|
|
749
|
+
};
|
|
750
|
+
|
|
751
|
+
const absorbStop = error => {
|
|
752
|
+
if (error instanceof Stop) {
|
|
753
|
+
stopped = true;
|
|
754
|
+
return true;
|
|
755
|
+
}
|
|
756
|
+
return false;
|
|
757
|
+
};
|
|
758
|
+
|
|
759
|
+
const writable = new WritableStream(
|
|
760
|
+
{
|
|
761
|
+
// `controller.signal` aborts during writer.abort() BEFORE the sink's
|
|
762
|
+
// abort() callback runs. The spec waits for in-flight write() to
|
|
763
|
+
// settle first — so if write() is awaiting pendingDrain, we'd
|
|
764
|
+
// deadlock unless the signal listener wakes it.
|
|
765
|
+
// Optional-chained because Bun ≤1.3.14 returns `undefined` for the
|
|
766
|
+
// controller's signal (spec-required per WHATWG Streams §4.5.2 but
|
|
767
|
+
// missing in Bun's builtin — see oven-sh/bun#31156 / PR #31157).
|
|
768
|
+
// Bun loses the abort-wakeup safety net until that lands, but the
|
|
769
|
+
// normal write/close/cancel paths still work.
|
|
770
|
+
start(controller) {
|
|
771
|
+
writableController = controller;
|
|
772
|
+
controller.signal?.addEventListener('abort', () => {
|
|
773
|
+
stopped = true;
|
|
774
|
+
unblockDrain();
|
|
775
|
+
});
|
|
776
|
+
},
|
|
777
|
+
async write(chunk) {
|
|
778
|
+
if (stopped) return;
|
|
779
|
+
try {
|
|
780
|
+
if (innerFns) {
|
|
781
|
+
const r = next(chunk, innerFns, 0, enqueue);
|
|
782
|
+
if (r) await r;
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
const r = processValue(fn(chunk));
|
|
786
|
+
if (r) await r;
|
|
787
|
+
} catch (error) {
|
|
788
|
+
if (absorbStop(error)) return;
|
|
789
|
+
// Propagate user-function errors to the readable side so downstream
|
|
790
|
+
// consumers (and pipeTo'd stages) learn — matches TransformStream.
|
|
791
|
+
errorReadable(error);
|
|
792
|
+
throw error;
|
|
793
|
+
}
|
|
794
|
+
},
|
|
795
|
+
async close() {
|
|
796
|
+
try {
|
|
797
|
+
if (!stopped) {
|
|
798
|
+
if (innerFns) {
|
|
799
|
+
const r = flush(innerFns, 0, enqueue);
|
|
800
|
+
if (r) await r;
|
|
801
|
+
} else if (isFlushable(fn)) {
|
|
802
|
+
const r = processValue(fn(none));
|
|
803
|
+
if (r) await r;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
} catch (error) {
|
|
807
|
+
if (!absorbStop(error)) {
|
|
808
|
+
errorReadable(error);
|
|
809
|
+
throw error;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
closeReadable();
|
|
813
|
+
},
|
|
814
|
+
abort(reason) {
|
|
815
|
+
stopped = true;
|
|
816
|
+
unblockDrain();
|
|
817
|
+
errorReadable(reason);
|
|
818
|
+
}
|
|
819
|
+
},
|
|
820
|
+
writableStrategy
|
|
821
|
+
);
|
|
822
|
+
|
|
823
|
+
return {readable, writable};
|
|
824
|
+
};
|
|
825
|
+
|
|
826
|
+
// @ts-self-types="./dataSource.d.ts"
|
|
827
|
+
|
|
828
|
+
const dataSource = fn => {
|
|
829
|
+
if (typeof fn == 'function') return fn;
|
|
830
|
+
if (fn) {
|
|
831
|
+
if (typeof fn[Symbol.asyncIterator] == 'function') return fn[Symbol.asyncIterator].bind(fn);
|
|
832
|
+
if (typeof fn[Symbol.iterator] == 'function') return fn[Symbol.iterator].bind(fn);
|
|
833
|
+
}
|
|
834
|
+
throw new TypeError('The argument should be a function or an iterable object.');
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
// @ts-self-types="./index.d.ts"
|
|
838
|
+
|
|
839
|
+
|
|
840
|
+
const {
|
|
841
|
+
isReadableWebStream,
|
|
842
|
+
isWritableWebStream,
|
|
843
|
+
isDuplexWebStream,
|
|
844
|
+
isReadableNodeStream,
|
|
845
|
+
isWritableNodeStream,
|
|
846
|
+
isDuplexNodeStream
|
|
847
|
+
} = defs;
|
|
848
|
+
|
|
849
|
+
const groupFunctions$1 = (output, fn, index, fns) => {
|
|
850
|
+
if (
|
|
851
|
+
isDuplexNodeStream(fn) ||
|
|
852
|
+
(!index && isReadableNodeStream(fn)) ||
|
|
853
|
+
(index === fns.length - 1 && isWritableNodeStream(fn))
|
|
854
|
+
) {
|
|
855
|
+
output.push(fn);
|
|
856
|
+
return output;
|
|
857
|
+
}
|
|
858
|
+
if (isDuplexWebStream(fn)) {
|
|
859
|
+
output.push(Duplex.fromWeb(fn, {objectMode: true}));
|
|
860
|
+
return output;
|
|
861
|
+
}
|
|
862
|
+
if (!index && isReadableWebStream(fn)) {
|
|
863
|
+
output.push(Readable.fromWeb(fn, {objectMode: true}));
|
|
864
|
+
return output;
|
|
865
|
+
}
|
|
866
|
+
if (index === fns.length - 1 && isWritableWebStream(fn)) {
|
|
867
|
+
output.push(Writable.fromWeb(fn, {objectMode: true}));
|
|
868
|
+
return output;
|
|
869
|
+
}
|
|
870
|
+
if (typeof fn != 'function')
|
|
871
|
+
throw TypeError('Item #' + index + ' is not a proper stream, nor a function.');
|
|
872
|
+
if (!output.length) output.push([]);
|
|
873
|
+
const last = output[output.length - 1];
|
|
874
|
+
if (Array.isArray(last)) {
|
|
875
|
+
last.push(fn);
|
|
876
|
+
} else {
|
|
877
|
+
output.push([fn]);
|
|
878
|
+
}
|
|
879
|
+
return output;
|
|
880
|
+
};
|
|
881
|
+
|
|
882
|
+
const produceStreams = item => {
|
|
883
|
+
if (Array.isArray(item)) {
|
|
884
|
+
if (!item.length) return null;
|
|
885
|
+
if (item.length == 1) return item[0] && /** @type {any} */ (chain$2).asStream(item[0]);
|
|
886
|
+
return /** @type {any} */ (chain$2).asStream(/** @type {any} */ (chain$2).gen(...item));
|
|
887
|
+
}
|
|
888
|
+
return item;
|
|
889
|
+
};
|
|
890
|
+
|
|
891
|
+
const wrapFunctions = (fn, index, fns) => {
|
|
892
|
+
if (
|
|
893
|
+
isDuplexNodeStream(fn) ||
|
|
894
|
+
(!index && isReadableNodeStream(fn)) ||
|
|
895
|
+
(index === fns.length - 1 && isWritableNodeStream(fn))
|
|
896
|
+
) {
|
|
897
|
+
return fn; // an acceptable stream
|
|
898
|
+
}
|
|
899
|
+
if (isDuplexWebStream(fn)) {
|
|
900
|
+
return Duplex.fromWeb(fn, {objectMode: true});
|
|
901
|
+
}
|
|
902
|
+
if (!index && isReadableWebStream(fn)) {
|
|
903
|
+
return Readable.fromWeb(fn, {objectMode: true});
|
|
904
|
+
}
|
|
905
|
+
if (index === fns.length - 1 && isWritableWebStream(fn)) {
|
|
906
|
+
return Writable.fromWeb(fn, {objectMode: true});
|
|
907
|
+
}
|
|
908
|
+
if (typeof fn == 'function') return /** @type {any} */ (chain$2).asStream(fn); // a function
|
|
909
|
+
throw TypeError('Item #' + index + ' is not a proper stream, nor a function.');
|
|
910
|
+
};
|
|
911
|
+
|
|
912
|
+
// default implementation of required stream methods
|
|
913
|
+
|
|
914
|
+
const write = (input, chunk, encoding, callback) => {
|
|
915
|
+
let error = null;
|
|
916
|
+
try {
|
|
917
|
+
input.write(chunk, encoding, e => callback(e || error));
|
|
918
|
+
} catch (e) {
|
|
919
|
+
error = e;
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
|
|
923
|
+
const final = (input, callback) => {
|
|
924
|
+
let error = null;
|
|
925
|
+
try {
|
|
926
|
+
input.end(null, null, e => callback(e || error));
|
|
927
|
+
} catch (e) {
|
|
928
|
+
error = e;
|
|
929
|
+
}
|
|
930
|
+
};
|
|
1412
931
|
|
|
1413
|
-
|
|
932
|
+
const read = output => {
|
|
933
|
+
output.resume();
|
|
934
|
+
};
|
|
1414
935
|
|
|
1415
|
-
|
|
1416
|
-
if (hasRequiredSrc) return src$1.exports;
|
|
1417
|
-
hasRequiredSrc = 1;
|
|
936
|
+
// the chain creator
|
|
1418
937
|
|
|
1419
|
-
|
|
1420
|
-
|
|
938
|
+
const chain$2 = (fns, options) => {
|
|
939
|
+
if (!Array.isArray(fns) || !fns.length) {
|
|
940
|
+
throw TypeError("Chain's first argument should be a non-empty array.");
|
|
941
|
+
}
|
|
1421
942
|
|
|
1422
|
-
|
|
943
|
+
fns = fns.flat(Infinity).filter(fn => fn);
|
|
944
|
+
|
|
945
|
+
const streams = (
|
|
946
|
+
options?.noGrouping
|
|
947
|
+
? fns.map(wrapFunctions)
|
|
948
|
+
: fns
|
|
949
|
+
.map(fn => (isFunctionList(fn) ? getFunctionList(fn) : fn))
|
|
950
|
+
.flat(Infinity)
|
|
951
|
+
.reduce(groupFunctions$1, [])
|
|
952
|
+
.map(produceStreams)
|
|
953
|
+
).filter(s => s),
|
|
954
|
+
input = streams[0],
|
|
955
|
+
output = streams.reduce((output, item) => (output && output.pipe(item)) || item);
|
|
956
|
+
|
|
957
|
+
let stream = null; // will be assigned later
|
|
958
|
+
|
|
959
|
+
let writeMethod = (chunk, encoding, callback) => write(input, chunk, encoding, callback),
|
|
960
|
+
finalMethod = callback => final(input, callback),
|
|
961
|
+
readMethod = () => read(output);
|
|
962
|
+
|
|
963
|
+
if (!isWritableNodeStream(input)) {
|
|
964
|
+
writeMethod = (_1, _2, callback) => callback(null);
|
|
965
|
+
finalMethod = callback => callback(null);
|
|
966
|
+
input.on('end', () => stream.end());
|
|
967
|
+
}
|
|
1423
968
|
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
}
|
|
969
|
+
if (isReadableNodeStream(output)) {
|
|
970
|
+
output.on('data', chunk => !stream.push(chunk) && output.pause());
|
|
971
|
+
output.on('end', () => stream.push(null));
|
|
972
|
+
} else {
|
|
973
|
+
readMethod = () => {}; // nop
|
|
974
|
+
output.on('finish', () => stream.push(null));
|
|
975
|
+
}
|
|
1428
976
|
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
977
|
+
stream = /** @type {Duplex & {streams: any[], input: any, output: any}} */ (
|
|
978
|
+
new Duplex({
|
|
979
|
+
writableObjectMode: true,
|
|
980
|
+
readableObjectMode: true,
|
|
981
|
+
...options,
|
|
982
|
+
readable: isReadableNodeStream(output),
|
|
983
|
+
writable: isWritableNodeStream(input),
|
|
984
|
+
write: writeMethod,
|
|
985
|
+
final: finalMethod,
|
|
986
|
+
read: readMethod
|
|
987
|
+
})
|
|
988
|
+
);
|
|
989
|
+
stream.streams = streams;
|
|
990
|
+
stream.input = input;
|
|
991
|
+
stream.output = output;
|
|
992
|
+
|
|
993
|
+
if (!isReadableNodeStream(output)) {
|
|
994
|
+
stream.resume();
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
// connect events
|
|
998
|
+
if (!options?.skipEvents) {
|
|
999
|
+
streams.forEach(item => item.on('error', error => stream.emit('error', error)));
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
return stream;
|
|
1003
|
+
};
|
|
1004
|
+
|
|
1005
|
+
// from defs.js
|
|
1006
|
+
chain$2.none = none;
|
|
1007
|
+
chain$2.stop = stop;
|
|
1008
|
+
chain$2.Stop = Stop;
|
|
1009
|
+
|
|
1010
|
+
chain$2.finalSymbol = finalSymbol;
|
|
1011
|
+
chain$2.finalValue = finalValue;
|
|
1012
|
+
chain$2.final = final$1;
|
|
1013
|
+
chain$2.isFinalValue = isFinalValue;
|
|
1014
|
+
chain$2.getFinalValue = getFinalValue;
|
|
1015
|
+
|
|
1016
|
+
chain$2.manySymbol = manySymbol;
|
|
1017
|
+
chain$2.many = many;
|
|
1018
|
+
chain$2.isMany = isMany;
|
|
1019
|
+
chain$2.getManyValues = getManyValues;
|
|
1020
|
+
|
|
1021
|
+
chain$2.flushSymbol = flushSymbol;
|
|
1022
|
+
chain$2.flushable = flushable;
|
|
1023
|
+
chain$2.isFlushable = isFlushable;
|
|
1024
|
+
|
|
1025
|
+
chain$2.fListSymbol = fListSymbol;
|
|
1026
|
+
chain$2.isFunctionList = isFunctionList;
|
|
1027
|
+
chain$2.getFunctionList = getFunctionList;
|
|
1028
|
+
chain$2.setFunctionList = setFunctionList;
|
|
1029
|
+
chain$2.clearFunctionList = clearFunctionList;
|
|
1030
|
+
|
|
1031
|
+
chain$2.toMany = toMany;
|
|
1032
|
+
chain$2.normalizeMany = normalizeMany;
|
|
1033
|
+
chain$2.combineMany = combineMany;
|
|
1034
|
+
chain$2.combineManyMut = combineManyMut;
|
|
1035
|
+
|
|
1036
|
+
chain$2.chain = chain$2; // for compatibility with 2.x
|
|
1037
|
+
chain$2.chainUnchecked = chain$2; // for TypeScript to bypass type checks
|
|
1038
|
+
chain$2.gen = gen;
|
|
1039
|
+
chain$2.asStream = asStream;
|
|
1040
|
+
chain$2.asWebStream = asWebStream;
|
|
1041
|
+
|
|
1042
|
+
chain$2.dataSource = dataSource;
|
|
1043
|
+
|
|
1044
|
+
// @ts-self-types="./fun.d.ts"
|
|
1045
|
+
|
|
1046
|
+
|
|
1047
|
+
const collect = (collect, fns) => {
|
|
1048
|
+
fns = fns
|
|
1049
|
+
.filter(fn => fn)
|
|
1050
|
+
.flat(Infinity)
|
|
1051
|
+
.map(fn => (isFunctionList(fn) ? getFunctionList(fn) : fn))
|
|
1052
|
+
.flat(Infinity);
|
|
1053
|
+
if (!fns.length) {
|
|
1054
|
+
fns = [x => x];
|
|
1055
|
+
}
|
|
1056
|
+
let flushed = false;
|
|
1057
|
+
let g = value => {
|
|
1058
|
+
if (flushed) throw Error('Call to a flushed pipe.');
|
|
1059
|
+
if (value !== none) {
|
|
1060
|
+
return next(value, fns, 0, collect);
|
|
1061
|
+
} else {
|
|
1062
|
+
flushed = true;
|
|
1063
|
+
return flush(fns, 0, collect);
|
|
1064
|
+
}
|
|
1065
|
+
};
|
|
1066
|
+
const needToFlush = fns.some(fn => isFlushable(fn));
|
|
1067
|
+
if (needToFlush) g = flushable(g);
|
|
1068
|
+
return setFunctionList(g, fns);
|
|
1069
|
+
};
|
|
1070
|
+
|
|
1071
|
+
const asArray = (...fns) => {
|
|
1072
|
+
let results = null;
|
|
1073
|
+
const f = collect(value => results.push(value), fns);
|
|
1074
|
+
let g = value => {
|
|
1075
|
+
results = [];
|
|
1076
|
+
const pending = f(value);
|
|
1077
|
+
if (pending && typeof pending.then == 'function') {
|
|
1078
|
+
return pending.then(() => {
|
|
1079
|
+
const r = results;
|
|
1080
|
+
results = null;
|
|
1081
|
+
return r;
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
const r = results;
|
|
1085
|
+
results = null;
|
|
1086
|
+
return r;
|
|
1087
|
+
};
|
|
1088
|
+
if (isFlushable(f)) g = flushable(g);
|
|
1089
|
+
return setFunctionList(g, getFunctionList(f));
|
|
1090
|
+
};
|
|
1091
|
+
|
|
1092
|
+
const fun = (...fns) => {
|
|
1093
|
+
const f = asArray(...fns);
|
|
1094
|
+
let g = value => {
|
|
1095
|
+
const result = /** @type {any} */ (f(value));
|
|
1096
|
+
if (result && typeof result.then == 'function') {
|
|
1097
|
+
return result.then(results => many(results));
|
|
1098
|
+
}
|
|
1099
|
+
return many(result);
|
|
1100
|
+
};
|
|
1101
|
+
if (isFlushable(f)) g = flushable(g);
|
|
1102
|
+
return setFunctionList(g, getFunctionList(f));
|
|
1103
|
+
};
|
|
1104
|
+
|
|
1105
|
+
// @ts-self-types="./index.d.ts"
|
|
1106
|
+
|
|
1107
|
+
|
|
1108
|
+
// Group consecutive functions into arrays (mirrors /node's groupFunctions) so the
|
|
1109
|
+
// produceStages step can bundle each group into a single asWebStream(gen(...group))
|
|
1110
|
+
// call — taking asWebStream's fused-executor path (exec.next) instead of one
|
|
1111
|
+
// TransformStream per function.
|
|
1112
|
+
const groupFunctions = (output, item, index, items) => {
|
|
1113
|
+
if (isDuplexWebStream$1(item)) {
|
|
1114
|
+
output.push(item);
|
|
1115
|
+
return output;
|
|
1116
|
+
}
|
|
1117
|
+
if (!index && isReadableWebStream$1(item)) {
|
|
1118
|
+
output.push({readable: item, writable: null});
|
|
1119
|
+
return output;
|
|
1120
|
+
}
|
|
1121
|
+
if (index === items.length - 1 && isWritableWebStream$1(item)) {
|
|
1122
|
+
output.push({readable: null, writable: item});
|
|
1123
|
+
return output;
|
|
1124
|
+
}
|
|
1125
|
+
if (typeof item !== 'function') {
|
|
1126
|
+
throw new TypeError(`Item #${index} is not a Web Streams object or function.`);
|
|
1127
|
+
}
|
|
1128
|
+
if (!output.length) output.push([]);
|
|
1129
|
+
const last = output[output.length - 1];
|
|
1130
|
+
if (Array.isArray(last)) {
|
|
1131
|
+
last.push(item);
|
|
1132
|
+
} else {
|
|
1133
|
+
output.push([item]);
|
|
1134
|
+
}
|
|
1135
|
+
return output;
|
|
1136
|
+
};
|
|
1137
|
+
|
|
1138
|
+
// Factory: returns a stage-producer bound to the chain's options. Options are
|
|
1139
|
+
// forwarded to every newly-wrapped asWebStream stage (existing stream items
|
|
1140
|
+
// passed in by the user keep their own settings — chain doesn't reconfigure them).
|
|
1141
|
+
const makeProduceStages = options => item => {
|
|
1142
|
+
if (Array.isArray(item)) {
|
|
1143
|
+
if (!item.length) return null;
|
|
1144
|
+
if (item.length === 1) return /** @type {any} */ (chain$1).asWebStream(item[0], options);
|
|
1145
|
+
return /** @type {any} */ (chain$1).asWebStream(/** @type {any} */ (chain$1).gen(...item), options);
|
|
1146
|
+
}
|
|
1147
|
+
return item;
|
|
1148
|
+
};
|
|
1149
|
+
|
|
1150
|
+
const chain$1 = (fns, options) => {
|
|
1151
|
+
if (!Array.isArray(fns) || !fns.length) {
|
|
1152
|
+
throw new TypeError("Chain's first argument should be a non-empty array.");
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
fns = fns
|
|
1156
|
+
.flat(Infinity)
|
|
1157
|
+
.filter(Boolean)
|
|
1158
|
+
.map(fn => (isFunctionList(fn) ? getFunctionList(fn) : fn))
|
|
1159
|
+
.flat(Infinity);
|
|
1160
|
+
|
|
1161
|
+
if (!fns.length) {
|
|
1162
|
+
throw new TypeError("Chain's first argument is empty after flattening.");
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
const stages = fns
|
|
1166
|
+
.reduce(groupFunctions, [])
|
|
1167
|
+
.map(makeProduceStages(options))
|
|
1168
|
+
.filter(s => s);
|
|
1169
|
+
|
|
1170
|
+
// Pipe stages together. pipeTo handles backpressure + error propagation.
|
|
1171
|
+
for (let i = 0; i < stages.length - 1; ++i) {
|
|
1172
|
+
const from = stages[i].readable;
|
|
1173
|
+
const to = stages[i + 1].writable;
|
|
1174
|
+
if (!from) {
|
|
1175
|
+
throw new TypeError(`Stage #${i} has no readable side; cannot pipe to next stage.`);
|
|
1176
|
+
}
|
|
1177
|
+
if (!to) {
|
|
1178
|
+
throw new TypeError(`Stage #${i + 1} has no writable side; cannot accept input.`);
|
|
1179
|
+
}
|
|
1180
|
+
from.pipeTo(to).catch(() => {});
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
const c = {
|
|
1184
|
+
readable: stages[stages.length - 1].readable,
|
|
1185
|
+
writable: stages[0].writable,
|
|
1186
|
+
streams: stages,
|
|
1187
|
+
input: stages[0],
|
|
1188
|
+
output: stages[stages.length - 1]
|
|
1189
|
+
};
|
|
1190
|
+
|
|
1191
|
+
return c;
|
|
1192
|
+
};
|
|
1193
|
+
|
|
1194
|
+
// Override-hook + ChainOutput parity statics (mirrors /node and /core).
|
|
1195
|
+
chain$1.none = none;
|
|
1196
|
+
chain$1.stop = stop;
|
|
1197
|
+
chain$1.Stop = Stop;
|
|
1198
|
+
|
|
1199
|
+
chain$1.finalSymbol = finalSymbol;
|
|
1200
|
+
chain$1.finalValue = finalValue;
|
|
1201
|
+
chain$1.final = final$1;
|
|
1202
|
+
chain$1.isFinalValue = isFinalValue;
|
|
1203
|
+
chain$1.getFinalValue = getFinalValue;
|
|
1204
|
+
|
|
1205
|
+
chain$1.manySymbol = manySymbol;
|
|
1206
|
+
chain$1.many = many;
|
|
1207
|
+
chain$1.isMany = isMany;
|
|
1208
|
+
chain$1.getManyValues = getManyValues;
|
|
1209
|
+
|
|
1210
|
+
chain$1.flushSymbol = flushSymbol;
|
|
1211
|
+
chain$1.flushable = flushable;
|
|
1212
|
+
chain$1.isFlushable = isFlushable;
|
|
1213
|
+
|
|
1214
|
+
chain$1.fListSymbol = fListSymbol;
|
|
1215
|
+
chain$1.isFunctionList = isFunctionList;
|
|
1216
|
+
chain$1.getFunctionList = getFunctionList;
|
|
1217
|
+
chain$1.setFunctionList = setFunctionList;
|
|
1218
|
+
chain$1.clearFunctionList = clearFunctionList;
|
|
1219
|
+
|
|
1220
|
+
chain$1.toMany = toMany;
|
|
1221
|
+
chain$1.normalizeMany = normalizeMany;
|
|
1222
|
+
chain$1.combineMany = combineMany;
|
|
1223
|
+
chain$1.combineManyMut = combineManyMut;
|
|
1224
|
+
|
|
1225
|
+
chain$1.chain = chain$1;
|
|
1226
|
+
chain$1.chainUnchecked = chain$1;
|
|
1227
|
+
chain$1.gen = gen;
|
|
1228
|
+
chain$1.fun = fun;
|
|
1229
|
+
chain$1.asWebStream = asWebStream;
|
|
1230
|
+
chain$1.dataSource = dataSource;
|
|
1231
|
+
|
|
1232
|
+
// @ts-self-types="./index.d.ts"
|
|
1233
|
+
|
|
1234
|
+
|
|
1235
|
+
const chain = (fns, _options) => {
|
|
1236
|
+
const flat = (Array.isArray(fns) ? fns : [])
|
|
1237
|
+
.flat(Infinity)
|
|
1238
|
+
.filter(Boolean)
|
|
1239
|
+
.map(fn => (isFunctionList(fn) ? getFunctionList(fn) : fn))
|
|
1240
|
+
.flat(Infinity);
|
|
1241
|
+
const g = gen(...flat);
|
|
1242
|
+
const c = async function* (input) {
|
|
1243
|
+
if (input == null) return;
|
|
1244
|
+
if (
|
|
1245
|
+
typeof input === 'string' ||
|
|
1246
|
+
(input[Symbol.asyncIterator] === undefined && input[Symbol.iterator] === undefined)
|
|
1247
|
+
) {
|
|
1248
|
+
yield* g(input);
|
|
1249
|
+
return;
|
|
1250
|
+
}
|
|
1251
|
+
for await (const value of input) yield* g(value);
|
|
1252
|
+
};
|
|
1253
|
+
c.streams = null;
|
|
1254
|
+
c.input = null;
|
|
1255
|
+
c.output = null;
|
|
1256
|
+
return c;
|
|
1257
|
+
};
|
|
1258
|
+
|
|
1259
|
+
// Override-hook + ChainOutput parity statics (mirrors the /node entry)
|
|
1260
|
+
chain.none = none;
|
|
1261
|
+
chain.stop = stop;
|
|
1262
|
+
chain.Stop = Stop;
|
|
1263
|
+
|
|
1264
|
+
chain.finalSymbol = finalSymbol;
|
|
1265
|
+
chain.finalValue = finalValue;
|
|
1266
|
+
chain.final = final$1;
|
|
1267
|
+
chain.isFinalValue = isFinalValue;
|
|
1268
|
+
chain.getFinalValue = getFinalValue;
|
|
1269
|
+
|
|
1270
|
+
chain.manySymbol = manySymbol;
|
|
1271
|
+
chain.many = many;
|
|
1272
|
+
chain.isMany = isMany;
|
|
1273
|
+
chain.getManyValues = getManyValues;
|
|
1274
|
+
|
|
1275
|
+
chain.flushSymbol = flushSymbol;
|
|
1276
|
+
chain.flushable = flushable;
|
|
1277
|
+
chain.isFlushable = isFlushable;
|
|
1278
|
+
|
|
1279
|
+
chain.fListSymbol = fListSymbol;
|
|
1280
|
+
chain.isFunctionList = isFunctionList;
|
|
1281
|
+
chain.getFunctionList = getFunctionList;
|
|
1282
|
+
chain.setFunctionList = setFunctionList;
|
|
1283
|
+
chain.clearFunctionList = clearFunctionList;
|
|
1284
|
+
|
|
1285
|
+
chain.toMany = toMany;
|
|
1286
|
+
chain.normalizeMany = normalizeMany;
|
|
1287
|
+
chain.combineMany = combineMany;
|
|
1288
|
+
chain.combineManyMut = combineManyMut;
|
|
1289
|
+
|
|
1290
|
+
chain.chain = chain;
|
|
1291
|
+
chain.chainUnchecked = chain;
|
|
1292
|
+
chain.gen = gen;
|
|
1293
|
+
chain.fun = fun;
|
|
1294
|
+
chain.dataSource = dataSource;
|
|
1295
|
+
|
|
1296
|
+
// @ts-self-types="./fixUtf8Stream.d.ts"
|
|
1297
|
+
|
|
1298
|
+
|
|
1299
|
+
const makeTextDecoderImpl = () => {
|
|
1300
|
+
const textDecoder = new TextDecoder();
|
|
1301
|
+
let input = '';
|
|
1302
|
+
return flushable(chunk => {
|
|
1303
|
+
if (chunk === none) {
|
|
1304
|
+
const result = input + textDecoder.decode();
|
|
1305
|
+
input = '';
|
|
1306
|
+
return result;
|
|
1307
|
+
}
|
|
1308
|
+
if (typeof chunk == 'string') {
|
|
1309
|
+
if (!input) return chunk;
|
|
1310
|
+
const result = input + chunk;
|
|
1311
|
+
input = '';
|
|
1312
|
+
return result;
|
|
1313
|
+
}
|
|
1314
|
+
if (chunk instanceof Uint8Array) {
|
|
1315
|
+
const result = input + textDecoder.decode(chunk, {stream: true});
|
|
1316
|
+
input = '';
|
|
1317
|
+
return result;
|
|
1318
|
+
}
|
|
1319
|
+
throw new TypeError('Expected a string or a Uint8Array');
|
|
1320
|
+
});
|
|
1321
|
+
};
|
|
1322
|
+
|
|
1323
|
+
const makeStringDecoderImpl = StringDecoder => () => {
|
|
1324
|
+
const stringDecoder = new StringDecoder();
|
|
1325
|
+
let input = '';
|
|
1326
|
+
return flushable(chunk => {
|
|
1327
|
+
if (chunk === none) {
|
|
1328
|
+
const result = input + stringDecoder.end();
|
|
1329
|
+
input = '';
|
|
1330
|
+
return result;
|
|
1331
|
+
}
|
|
1332
|
+
if (typeof chunk == 'string') {
|
|
1333
|
+
if (!input) return chunk;
|
|
1334
|
+
const result = input + chunk;
|
|
1335
|
+
input = '';
|
|
1336
|
+
return result;
|
|
1337
|
+
}
|
|
1338
|
+
if (chunk instanceof Uint8Array) {
|
|
1339
|
+
const result = input + stringDecoder.write(chunk);
|
|
1340
|
+
input = '';
|
|
1341
|
+
return result;
|
|
1342
|
+
}
|
|
1343
|
+
throw new TypeError('Expected a string or a Uint8Array');
|
|
1344
|
+
});
|
|
1345
|
+
};
|
|
1346
|
+
|
|
1347
|
+
// Default to TextDecoder — works in every runtime (Node, Bun, Deno, browser).
|
|
1348
|
+
// On Node, asynchronously upgrade to StringDecoder which is 2–4× faster on the
|
|
1349
|
+
// decoder hot path. Fire-and-forget: composing fixUtf8Stream() before the
|
|
1350
|
+
// upgrade lands yields a TextDecoder-backed stage (still correct); after, a
|
|
1351
|
+
// StringDecoder-backed one. Callers needing the fast path on Node can
|
|
1352
|
+
// `await whenReady()` before composition.
|
|
1353
|
+
//
|
|
1354
|
+
// Bun and Deno stay on TextDecoder per benchmarks: Bun is a wash, Deno
|
|
1355
|
+
// actively prefers TextDecoder over its node-compat StringDecoder.
|
|
1356
|
+
|
|
1357
|
+
let impl = makeTextDecoderImpl;
|
|
1358
|
+
|
|
1359
|
+
const isDeno = typeof globalThis['Deno'] == 'object' && globalThis['Deno']?.version;
|
|
1360
|
+
const isBun = typeof globalThis['Bun'] == 'object' && globalThis['Bun']?.version;
|
|
1361
|
+
const isNode = !isDeno && !isBun && typeof process == 'object' && process?.versions?.node;
|
|
1362
|
+
|
|
1363
|
+
isNode
|
|
1364
|
+
? import('node:string_decoder').then(
|
|
1365
|
+
({StringDecoder}) => {
|
|
1366
|
+
impl = makeStringDecoderImpl(StringDecoder);
|
|
1367
|
+
},
|
|
1368
|
+
() => {} // squelch — stick with TextDecoder
|
|
1369
|
+
)
|
|
1370
|
+
: Promise.resolve();
|
|
1371
|
+
|
|
1372
|
+
const fixUtf8Stream = () => impl();
|
|
1373
|
+
|
|
1374
|
+
// @ts-self-types="./parser.d.ts"
|
|
1375
|
+
|
|
1376
|
+
|
|
1377
|
+
const patterns = {
|
|
1378
|
+
value1: /[\"\{\[\]\-\d]|true\b|false\b|null\b|\s{1,256}/y,
|
|
1379
|
+
string: /[^\x00-\x1f\"\\]{1,256}|\\[bfnrt\"\\\/]|\\u[\da-fA-F]{4}|\"/y,
|
|
1380
|
+
numberStart: /\d/y,
|
|
1381
|
+
numberDigit: /\d{0,256}/y,
|
|
1382
|
+
numberFraction: /[\.eE]/y,
|
|
1383
|
+
numberExponent: /[eE]/y,
|
|
1384
|
+
numberExpSign: /[-+]/y
|
|
1385
|
+
};
|
|
1386
|
+
const MAX_PATTERN_SIZE = 16;
|
|
1387
|
+
|
|
1388
|
+
patterns.numberFracStart = patterns.numberExpStart = patterns.numberStart;
|
|
1389
|
+
patterns.numberFracDigit = patterns.numberExpDigit = patterns.numberDigit;
|
|
1390
|
+
|
|
1391
|
+
const expected = {object: 'objectStop', array: 'arrayStop', '': 'done'};
|
|
1392
|
+
|
|
1393
|
+
const tokenStartObject = {name: 'startObject'},
|
|
1394
|
+
tokenEndObject = {name: 'endObject'},
|
|
1395
|
+
tokenStartArray = {name: 'startArray'},
|
|
1396
|
+
tokenEndArray = {name: 'endArray'},
|
|
1397
|
+
tokenStartString = {name: 'startString'},
|
|
1398
|
+
tokenEndString = {name: 'endString'},
|
|
1399
|
+
tokenStartNumber = {name: 'startNumber'},
|
|
1400
|
+
tokenEndNumber = {name: 'endNumber'},
|
|
1401
|
+
tokenStartKey = {name: 'startKey'},
|
|
1402
|
+
tokenEndKey = {name: 'endKey'},
|
|
1403
|
+
literalTokens = {
|
|
1404
|
+
true: {name: 'trueValue', value: true},
|
|
1405
|
+
false: {name: 'falseValue', value: false},
|
|
1406
|
+
null: {name: 'nullValue', value: null}
|
|
1407
|
+
};
|
|
1408
|
+
|
|
1409
|
+
// long hexadecimal codes: \uXXXX
|
|
1410
|
+
const fromHex = s => String.fromCharCode(parseInt(s.slice(2), 16));
|
|
1411
|
+
|
|
1412
|
+
// short codes: \b \f \n \r \t \" \\ \/
|
|
1413
|
+
const codes = {b: '\b', f: '\f', n: '\n', r: '\r', t: '\t', '"': '"', '\\': '\\', '/': '/'};
|
|
1414
|
+
|
|
1415
|
+
// ASCII code points of the JSON syntax characters (each folds to a constant at load)
|
|
1416
|
+
const ASCII_TAB = '\t'.charCodeAt(0),
|
|
1417
|
+
ASCII_LF = '\n'.charCodeAt(0),
|
|
1418
|
+
ASCII_CR = '\r'.charCodeAt(0),
|
|
1419
|
+
ASCII_SPACE = ' '.charCodeAt(0),
|
|
1420
|
+
ASCII_QUOTE = '"'.charCodeAt(0),
|
|
1421
|
+
ASCII_BACKSLASH = '\\'.charCodeAt(0),
|
|
1422
|
+
ASCII_OPEN_BRACE = '{'.charCodeAt(0),
|
|
1423
|
+
ASCII_CLOSE_BRACE = '}'.charCodeAt(0),
|
|
1424
|
+
ASCII_OPEN_BRACKET = '['.charCodeAt(0),
|
|
1425
|
+
ASCII_CLOSE_BRACKET = ']'.charCodeAt(0),
|
|
1426
|
+
ASCII_MINUS = '-'.charCodeAt(0),
|
|
1427
|
+
ASCII_COLON = ':'.charCodeAt(0),
|
|
1428
|
+
ASCII_COMMA = ','.charCodeAt(0),
|
|
1429
|
+
ASCII_ZERO = '0'.charCodeAt(0),
|
|
1430
|
+
ASCII_NINE = '9'.charCodeAt(0),
|
|
1431
|
+
ASCII_UPPER_A = 'A'.charCodeAt(0),
|
|
1432
|
+
ASCII_UPPER_F = 'F'.charCodeAt(0),
|
|
1433
|
+
ASCII_LOWER_A = 'a'.charCodeAt(0),
|
|
1434
|
+
ASCII_LOWER_F = 'f'.charCodeAt(0),
|
|
1435
|
+
ASCII_LOWER_N = 'n'.charCodeAt(0),
|
|
1436
|
+
ASCII_LOWER_T = 't'.charCodeAt(0),
|
|
1437
|
+
ASCII_LOWER_U = 'u'.charCodeAt(0);
|
|
1438
|
+
|
|
1439
|
+
// fast-path helpers
|
|
1440
|
+
// char codes that legally terminate a number lexeme: , } ] and JSON whitespace
|
|
1441
|
+
const TERM = [];
|
|
1442
|
+
for (const ch of ',}] \t\n\r') TERM[ch.charCodeAt(0)] = 1;
|
|
1443
|
+
const numberFull = /-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][-+]?\d+)?/y;
|
|
1444
|
+
const HEX = c => (c >= ASCII_ZERO && c <= ASCII_NINE) || (c >= ASCII_UPPER_A && c <= ASCII_UPPER_F) || (c >= ASCII_LOWER_A && c <= ASCII_LOWER_F);
|
|
1445
|
+
|
|
1446
|
+
const jsonParser = options => {
|
|
1447
|
+
let packKeys = true,
|
|
1448
|
+
packStrings = true,
|
|
1449
|
+
packNumbers = true,
|
|
1450
|
+
streamKeys = true,
|
|
1451
|
+
streamStrings = true,
|
|
1452
|
+
streamNumbers = true,
|
|
1453
|
+
jsonStreaming = false;
|
|
1454
|
+
|
|
1455
|
+
if (options) {
|
|
1456
|
+
'packValues' in options && (packKeys = packStrings = packNumbers = options.packValues);
|
|
1457
|
+
'packKeys' in options && (packKeys = options.packKeys);
|
|
1458
|
+
'packStrings' in options && (packStrings = options.packStrings);
|
|
1459
|
+
'packNumbers' in options && (packNumbers = options.packNumbers);
|
|
1460
|
+
'streamValues' in options && (streamKeys = streamStrings = streamNumbers = options.streamValues);
|
|
1461
|
+
'streamKeys' in options && (streamKeys = options.streamKeys);
|
|
1462
|
+
'streamStrings' in options && (streamStrings = options.streamStrings);
|
|
1463
|
+
'streamNumbers' in options && (streamNumbers = options.streamNumbers);
|
|
1464
|
+
jsonStreaming = options.jsonStreaming;
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
!packKeys && (streamKeys = true);
|
|
1468
|
+
!packStrings && (streamStrings = true);
|
|
1469
|
+
!packNumbers && (streamNumbers = true);
|
|
1470
|
+
|
|
1471
|
+
let done = false,
|
|
1472
|
+
expect = jsonStreaming ? 'done' : 'value',
|
|
1473
|
+
parent = '',
|
|
1474
|
+
openNumber = false,
|
|
1475
|
+
accumulator = '',
|
|
1476
|
+
buffer = '';
|
|
1477
|
+
|
|
1478
|
+
const stack = [];
|
|
1479
|
+
|
|
1480
|
+
return flushable(buf => {
|
|
1481
|
+
const tokens = [];
|
|
1482
|
+
|
|
1483
|
+
if (buf === none) {
|
|
1484
|
+
done = true;
|
|
1485
|
+
} else {
|
|
1486
|
+
buffer += buf;
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
let match,
|
|
1490
|
+
fm,
|
|
1491
|
+
s,
|
|
1492
|
+
e,
|
|
1493
|
+
q,
|
|
1494
|
+
rs,
|
|
1495
|
+
cc,
|
|
1496
|
+
value,
|
|
1497
|
+
index = 0;
|
|
1498
|
+
|
|
1499
|
+
main: for (;;) {
|
|
1500
|
+
switch (expect) {
|
|
1501
|
+
case 'value1':
|
|
1502
|
+
case 'value': {
|
|
1503
|
+
// skip whitespace
|
|
1504
|
+
while (index < buffer.length) {
|
|
1505
|
+
cc = buffer.charCodeAt(index);
|
|
1506
|
+
if (cc === ASCII_SPACE || cc === ASCII_TAB || cc === ASCII_LF || cc === ASCII_CR) {
|
|
1507
|
+
++index;
|
|
1508
|
+
continue;
|
|
1509
|
+
}
|
|
1510
|
+
break;
|
|
1511
|
+
}
|
|
1512
|
+
if (index >= buffer.length) {
|
|
1513
|
+
if (done) throw new Error('Parser has expected a value');
|
|
1514
|
+
break main; // wait for more input
|
|
1515
|
+
}
|
|
1516
|
+
cc = buffer.charCodeAt(index);
|
|
1517
|
+
if (cc === ASCII_QUOTE) {
|
|
1518
|
+
// string: charCodeAt whole-string scan (decodes escapes)
|
|
1519
|
+
q = index + 1;
|
|
1520
|
+
rs = q;
|
|
1521
|
+
s = '';
|
|
1522
|
+
for (;;) {
|
|
1523
|
+
if (q >= buffer.length) {
|
|
1524
|
+
q = -1;
|
|
1525
|
+
break;
|
|
1526
|
+
}
|
|
1527
|
+
e = buffer.charCodeAt(q);
|
|
1528
|
+
if (e === ASCII_QUOTE) {
|
|
1529
|
+
s += buffer.slice(rs, q);
|
|
1530
|
+
break;
|
|
1531
|
+
}
|
|
1532
|
+
if (e < ASCII_SPACE) {
|
|
1533
|
+
q = -1;
|
|
1534
|
+
break;
|
|
1535
|
+
}
|
|
1536
|
+
if (e === ASCII_BACKSLASH) {
|
|
1537
|
+
if (q + 1 >= buffer.length) {
|
|
1538
|
+
q = -1;
|
|
1539
|
+
break;
|
|
1540
|
+
}
|
|
1541
|
+
cc = buffer.charCodeAt(q + 1);
|
|
1542
|
+
if (cc === ASCII_LOWER_U) {
|
|
1543
|
+
if (
|
|
1544
|
+
q + 6 > buffer.length ||
|
|
1545
|
+
!(HEX(buffer.charCodeAt(q + 2)) && HEX(buffer.charCodeAt(q + 3)) && HEX(buffer.charCodeAt(q + 4)) && HEX(buffer.charCodeAt(q + 5)))
|
|
1546
|
+
) {
|
|
1547
|
+
q = -1;
|
|
1548
|
+
break;
|
|
1549
|
+
}
|
|
1550
|
+
s += buffer.slice(rs, q) + String.fromCharCode(parseInt(buffer.slice(q + 2, q + 6), 16));
|
|
1551
|
+
q += 6;
|
|
1552
|
+
} else {
|
|
1553
|
+
value = codes[buffer.charAt(q + 1)];
|
|
1554
|
+
if (value === undefined) {
|
|
1555
|
+
q = -1;
|
|
1556
|
+
break;
|
|
1557
|
+
}
|
|
1558
|
+
s += buffer.slice(rs, q) + value;
|
|
1559
|
+
q += 2;
|
|
1560
|
+
}
|
|
1561
|
+
rs = q;
|
|
1562
|
+
continue;
|
|
1563
|
+
}
|
|
1564
|
+
++q;
|
|
1565
|
+
}
|
|
1566
|
+
if (q >= 0) {
|
|
1567
|
+
if (streamStrings) {
|
|
1568
|
+
tokens.push(tokenStartString);
|
|
1569
|
+
if (s) tokens.push({name: 'stringChunk', value: s});
|
|
1570
|
+
tokens.push(tokenEndString);
|
|
1571
|
+
}
|
|
1572
|
+
if (packStrings) tokens.push({name: 'stringValue', value: s});
|
|
1573
|
+
index = q + 1;
|
|
1574
|
+
expect = expected[parent];
|
|
1575
|
+
continue main;
|
|
1576
|
+
}
|
|
1577
|
+
// fall back to incremental string machine
|
|
1578
|
+
if (streamStrings) tokens.push(tokenStartString);
|
|
1579
|
+
expect = 'string';
|
|
1580
|
+
++index;
|
|
1581
|
+
continue main;
|
|
1582
|
+
}
|
|
1583
|
+
if (cc === ASCII_OPEN_BRACE) {
|
|
1584
|
+
tokens.push(tokenStartObject);
|
|
1585
|
+
stack.push(parent);
|
|
1586
|
+
parent = 'object';
|
|
1587
|
+
expect = 'key1';
|
|
1588
|
+
++index;
|
|
1589
|
+
continue main;
|
|
1590
|
+
}
|
|
1591
|
+
if (cc === ASCII_OPEN_BRACKET) {
|
|
1592
|
+
tokens.push(tokenStartArray);
|
|
1593
|
+
stack.push(parent);
|
|
1594
|
+
parent = 'array';
|
|
1595
|
+
expect = 'value1';
|
|
1596
|
+
++index;
|
|
1597
|
+
continue main;
|
|
1598
|
+
}
|
|
1599
|
+
if (cc === ASCII_CLOSE_BRACKET) {
|
|
1600
|
+
if (expect !== 'value1') throw new Error("Parser cannot parse input: unexpected token ']'");
|
|
1601
|
+
tokens.push(tokenEndArray);
|
|
1602
|
+
parent = stack.pop();
|
|
1603
|
+
expect = expected[parent];
|
|
1604
|
+
++index;
|
|
1605
|
+
continue main;
|
|
1606
|
+
}
|
|
1607
|
+
if (cc === ASCII_MINUS || (cc >= ASCII_ZERO && cc <= ASCII_NINE)) {
|
|
1608
|
+
// number: try whole-number fast path (only with a clear terminator in buffer)
|
|
1609
|
+
numberFull.lastIndex = index;
|
|
1610
|
+
fm = numberFull.exec(buffer);
|
|
1611
|
+
if (fm) {
|
|
1612
|
+
e = index + fm[0].length;
|
|
1613
|
+
if (e < buffer.length && TERM[buffer.charCodeAt(e)]) {
|
|
1614
|
+
s = fm[0];
|
|
1615
|
+
if (streamNumbers) tokens.push(tokenStartNumber, {name: 'numberChunk', value: s}, tokenEndNumber);
|
|
1616
|
+
if (packNumbers) tokens.push({name: 'numberValue', value: s});
|
|
1617
|
+
index = e;
|
|
1618
|
+
expect = expected[parent];
|
|
1619
|
+
continue main;
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
// fall back to incremental number machine (mirrors the value1 branches)
|
|
1623
|
+
openNumber = true;
|
|
1624
|
+
if (cc === ASCII_MINUS) {
|
|
1625
|
+
if (streamNumbers) tokens.push(tokenStartNumber, {name: 'numberChunk', value: '-'});
|
|
1626
|
+
packNumbers && (accumulator = '-');
|
|
1627
|
+
expect = 'numberStart';
|
|
1628
|
+
} else if (cc === ASCII_ZERO) {
|
|
1629
|
+
if (streamNumbers) tokens.push(tokenStartNumber, {name: 'numberChunk', value: '0'});
|
|
1630
|
+
packNumbers && (accumulator = '0');
|
|
1631
|
+
expect = 'numberFraction';
|
|
1632
|
+
} else {
|
|
1633
|
+
s = buffer.charAt(index);
|
|
1634
|
+
if (streamNumbers) tokens.push(tokenStartNumber, {name: 'numberChunk', value: s});
|
|
1635
|
+
packNumbers && (accumulator = s);
|
|
1636
|
+
expect = 'numberDigit';
|
|
1637
|
+
}
|
|
1638
|
+
++index;
|
|
1639
|
+
continue main;
|
|
1640
|
+
}
|
|
1641
|
+
if (cc === ASCII_LOWER_T || cc === ASCII_LOWER_F || cc === ASCII_LOWER_N) {
|
|
1642
|
+
// true / false / null — reuse the value1 regex for exact \b + wait semantics
|
|
1643
|
+
patterns.value1.lastIndex = index;
|
|
1644
|
+
match = patterns.value1.exec(buffer);
|
|
1645
|
+
if (!match) {
|
|
1646
|
+
if (done || index + MAX_PATTERN_SIZE < buffer.length) {
|
|
1647
|
+
throw new Error('Parser cannot parse input: expected a value');
|
|
1648
|
+
}
|
|
1649
|
+
break main; // wait for more input
|
|
1650
|
+
}
|
|
1651
|
+
value = match[0];
|
|
1652
|
+
if (buffer.length - index === value.length && !done) break main; // wait for boundary
|
|
1653
|
+
tokens.push(literalTokens[value]);
|
|
1654
|
+
expect = expected[parent];
|
|
1655
|
+
index += value.length;
|
|
1656
|
+
continue main;
|
|
1657
|
+
}
|
|
1658
|
+
throw new Error('Parser cannot parse input: expected a value');
|
|
1659
|
+
}
|
|
1660
|
+
// incremental string body (escapes / long / cross-chunk)
|
|
1661
|
+
case 'keyVal':
|
|
1662
|
+
case 'string':
|
|
1663
|
+
patterns.string.lastIndex = index;
|
|
1664
|
+
match = patterns.string.exec(buffer);
|
|
1665
|
+
if (!match) {
|
|
1666
|
+
if (index < buffer.length && (done || buffer.length - index >= 6)) throw new Error('Parser cannot parse input: escaped characters');
|
|
1667
|
+
if (done) throw new Error('Parser has expected a string value');
|
|
1668
|
+
break main; // wait for more input
|
|
1669
|
+
}
|
|
1670
|
+
value = match[0];
|
|
1671
|
+
if (value === '"') {
|
|
1672
|
+
if (expect === 'keyVal') {
|
|
1673
|
+
if (streamKeys) tokens.push(tokenEndKey);
|
|
1674
|
+
if (packKeys) {
|
|
1675
|
+
tokens.push({name: 'keyValue', value: accumulator});
|
|
1676
|
+
accumulator = '';
|
|
1677
|
+
}
|
|
1678
|
+
expect = 'colon';
|
|
1679
|
+
} else {
|
|
1680
|
+
if (streamStrings) tokens.push(tokenEndString);
|
|
1681
|
+
if (packStrings) {
|
|
1682
|
+
tokens.push({name: 'stringValue', value: accumulator});
|
|
1683
|
+
accumulator = '';
|
|
1684
|
+
}
|
|
1685
|
+
expect = expected[parent];
|
|
1686
|
+
}
|
|
1687
|
+
} else if (value.length > 1 && value.charAt(0) === '\\') {
|
|
1688
|
+
const t = value.length == 2 ? codes[value.charAt(1)] : fromHex(value);
|
|
1689
|
+
if (expect === 'keyVal' ? streamKeys : streamStrings) {
|
|
1690
|
+
tokens.push({name: 'stringChunk', value: t});
|
|
1691
|
+
}
|
|
1692
|
+
if (expect === 'keyVal' ? packKeys : packStrings) {
|
|
1693
|
+
accumulator += t;
|
|
1694
|
+
}
|
|
1695
|
+
} else {
|
|
1696
|
+
if (expect === 'keyVal' ? streamKeys : streamStrings) {
|
|
1697
|
+
tokens.push({name: 'stringChunk', value});
|
|
1698
|
+
}
|
|
1699
|
+
if (expect === 'keyVal' ? packKeys : packStrings) {
|
|
1700
|
+
accumulator += value;
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
index += value.length;
|
|
1704
|
+
break;
|
|
1705
|
+
case 'key1':
|
|
1706
|
+
case 'key': {
|
|
1707
|
+
while (index < buffer.length) {
|
|
1708
|
+
cc = buffer.charCodeAt(index);
|
|
1709
|
+
if (cc === ASCII_SPACE || cc === ASCII_TAB || cc === ASCII_LF || cc === ASCII_CR) {
|
|
1710
|
+
++index;
|
|
1711
|
+
continue;
|
|
1712
|
+
}
|
|
1713
|
+
break;
|
|
1714
|
+
}
|
|
1715
|
+
if (index >= buffer.length) {
|
|
1716
|
+
if (done) throw new Error('Parser cannot parse input: expected an object key');
|
|
1717
|
+
break main; // wait for more input
|
|
1718
|
+
}
|
|
1719
|
+
cc = buffer.charCodeAt(index);
|
|
1720
|
+
if (cc === ASCII_QUOTE) {
|
|
1721
|
+
// key string: charCodeAt whole-key scan (decodes escapes)
|
|
1722
|
+
q = index + 1;
|
|
1723
|
+
rs = q;
|
|
1724
|
+
s = '';
|
|
1725
|
+
for (;;) {
|
|
1726
|
+
if (q >= buffer.length) {
|
|
1727
|
+
q = -1;
|
|
1728
|
+
break;
|
|
1729
|
+
}
|
|
1730
|
+
e = buffer.charCodeAt(q);
|
|
1731
|
+
if (e === ASCII_QUOTE) {
|
|
1732
|
+
s += buffer.slice(rs, q);
|
|
1733
|
+
break;
|
|
1734
|
+
}
|
|
1735
|
+
if (e < ASCII_SPACE) {
|
|
1736
|
+
q = -1;
|
|
1737
|
+
break;
|
|
1738
|
+
}
|
|
1739
|
+
if (e === ASCII_BACKSLASH) {
|
|
1740
|
+
if (q + 1 >= buffer.length) {
|
|
1741
|
+
q = -1;
|
|
1742
|
+
break;
|
|
1743
|
+
}
|
|
1744
|
+
cc = buffer.charCodeAt(q + 1);
|
|
1745
|
+
if (cc === ASCII_LOWER_U) {
|
|
1746
|
+
if (
|
|
1747
|
+
q + 6 > buffer.length ||
|
|
1748
|
+
!(HEX(buffer.charCodeAt(q + 2)) && HEX(buffer.charCodeAt(q + 3)) && HEX(buffer.charCodeAt(q + 4)) && HEX(buffer.charCodeAt(q + 5)))
|
|
1749
|
+
) {
|
|
1750
|
+
q = -1;
|
|
1751
|
+
break;
|
|
1752
|
+
}
|
|
1753
|
+
s += buffer.slice(rs, q) + String.fromCharCode(parseInt(buffer.slice(q + 2, q + 6), 16));
|
|
1754
|
+
q += 6;
|
|
1755
|
+
} else {
|
|
1756
|
+
value = codes[buffer.charAt(q + 1)];
|
|
1757
|
+
if (value === undefined) {
|
|
1758
|
+
q = -1;
|
|
1759
|
+
break;
|
|
1760
|
+
}
|
|
1761
|
+
s += buffer.slice(rs, q) + value;
|
|
1762
|
+
q += 2;
|
|
1763
|
+
}
|
|
1764
|
+
rs = q;
|
|
1765
|
+
continue;
|
|
1766
|
+
}
|
|
1767
|
+
++q;
|
|
1768
|
+
}
|
|
1769
|
+
if (q >= 0) {
|
|
1770
|
+
if (streamKeys) {
|
|
1771
|
+
tokens.push(tokenStartKey);
|
|
1772
|
+
if (s) tokens.push({name: 'stringChunk', value: s});
|
|
1773
|
+
tokens.push(tokenEndKey);
|
|
1774
|
+
}
|
|
1775
|
+
if (packKeys) tokens.push({name: 'keyValue', value: s});
|
|
1776
|
+
index = q + 1;
|
|
1777
|
+
expect = 'colon';
|
|
1778
|
+
continue main;
|
|
1779
|
+
}
|
|
1780
|
+
if (streamKeys) tokens.push(tokenStartKey);
|
|
1781
|
+
expect = 'keyVal';
|
|
1782
|
+
++index;
|
|
1783
|
+
continue main;
|
|
1784
|
+
}
|
|
1785
|
+
if (cc === ASCII_CLOSE_BRACE) {
|
|
1786
|
+
if (expect !== 'key1') throw new Error("Parser cannot parse input: unexpected token '}'");
|
|
1787
|
+
tokens.push(tokenEndObject);
|
|
1788
|
+
parent = stack.pop();
|
|
1789
|
+
expect = expected[parent];
|
|
1790
|
+
++index;
|
|
1791
|
+
continue main;
|
|
1792
|
+
}
|
|
1793
|
+
throw new Error('Parser cannot parse input: expected an object key');
|
|
1794
|
+
}
|
|
1795
|
+
case 'colon': {
|
|
1796
|
+
while (index < buffer.length) {
|
|
1797
|
+
cc = buffer.charCodeAt(index);
|
|
1798
|
+
if (cc === ASCII_SPACE || cc === ASCII_TAB || cc === ASCII_LF || cc === ASCII_CR) {
|
|
1799
|
+
++index;
|
|
1800
|
+
continue;
|
|
1801
|
+
}
|
|
1802
|
+
break;
|
|
1803
|
+
}
|
|
1804
|
+
if (index >= buffer.length) {
|
|
1805
|
+
if (done) throw new Error("Parser cannot parse input: expected ':'");
|
|
1806
|
+
break main; // wait for more input
|
|
1807
|
+
}
|
|
1808
|
+
cc = buffer.charCodeAt(index);
|
|
1809
|
+
if (cc === ASCII_COLON) {
|
|
1810
|
+
expect = 'value';
|
|
1811
|
+
++index;
|
|
1812
|
+
continue main;
|
|
1813
|
+
}
|
|
1814
|
+
throw new Error("Parser cannot parse input: expected ':'");
|
|
1815
|
+
}
|
|
1816
|
+
case 'arrayStop':
|
|
1817
|
+
case 'objectStop': {
|
|
1818
|
+
while (index < buffer.length) {
|
|
1819
|
+
cc = buffer.charCodeAt(index);
|
|
1820
|
+
if (cc === ASCII_SPACE || cc === ASCII_TAB || cc === ASCII_LF || cc === ASCII_CR) {
|
|
1821
|
+
++index;
|
|
1822
|
+
continue;
|
|
1823
|
+
}
|
|
1824
|
+
break;
|
|
1825
|
+
}
|
|
1826
|
+
if (index >= buffer.length) {
|
|
1827
|
+
if (done) throw new Error("Parser cannot parse input: expected ','");
|
|
1828
|
+
break main; // wait for more input
|
|
1829
|
+
}
|
|
1830
|
+
if (openNumber) {
|
|
1831
|
+
if (streamNumbers) tokens.push(tokenEndNumber);
|
|
1832
|
+
openNumber = false;
|
|
1833
|
+
if (packNumbers) {
|
|
1834
|
+
tokens.push({name: 'numberValue', value: accumulator});
|
|
1835
|
+
accumulator = '';
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
cc = buffer.charCodeAt(index);
|
|
1839
|
+
if (cc === ASCII_COMMA) {
|
|
1840
|
+
expect = expect === 'arrayStop' ? 'value' : 'key';
|
|
1841
|
+
++index;
|
|
1842
|
+
continue main;
|
|
1843
|
+
}
|
|
1844
|
+
if (cc === ASCII_CLOSE_BRACE || cc === ASCII_CLOSE_BRACKET) {
|
|
1845
|
+
if (cc === ASCII_CLOSE_BRACE ? expect === 'arrayStop' : expect !== 'arrayStop') {
|
|
1846
|
+
throw new Error("Parser cannot parse input: expected '" + (expect === 'arrayStop' ? ']' : '}') + "'");
|
|
1847
|
+
}
|
|
1848
|
+
tokens.push(cc === ASCII_CLOSE_BRACE ? tokenEndObject : tokenEndArray);
|
|
1849
|
+
parent = stack.pop();
|
|
1850
|
+
expect = expected[parent];
|
|
1851
|
+
++index;
|
|
1852
|
+
continue main;
|
|
1853
|
+
}
|
|
1854
|
+
throw new Error("Parser cannot parse input: expected ','");
|
|
1855
|
+
}
|
|
1856
|
+
// number chunks — cross-chunk / fallback
|
|
1857
|
+
case 'numberStart': // [0-9]
|
|
1858
|
+
patterns.numberStart.lastIndex = index;
|
|
1859
|
+
match = patterns.numberStart.exec(buffer);
|
|
1860
|
+
if (!match) {
|
|
1861
|
+
if (index < buffer.length || done) throw new Error('Parser cannot parse input: expected a starting digit');
|
|
1862
|
+
break main; // wait for more input
|
|
1863
|
+
}
|
|
1864
|
+
value = match[0];
|
|
1865
|
+
if (streamNumbers) tokens.push({name: 'numberChunk', value});
|
|
1866
|
+
packNumbers && (accumulator += value);
|
|
1867
|
+
expect = value === '0' ? 'numberFraction' : 'numberDigit';
|
|
1868
|
+
index += value.length;
|
|
1869
|
+
break;
|
|
1870
|
+
case 'numberDigit': // [0-9]*
|
|
1871
|
+
patterns.numberDigit.lastIndex = index;
|
|
1872
|
+
match = patterns.numberDigit.exec(buffer);
|
|
1873
|
+
if (!match) {
|
|
1874
|
+
if (index < buffer.length || done) throw new Error('Parser cannot parse input: expected a digit');
|
|
1875
|
+
break main; // wait for more input
|
|
1876
|
+
}
|
|
1877
|
+
value = match[0];
|
|
1878
|
+
if (value) {
|
|
1879
|
+
if (streamNumbers) tokens.push({name: 'numberChunk', value});
|
|
1880
|
+
packNumbers && (accumulator += value);
|
|
1881
|
+
index += value.length;
|
|
1882
|
+
} else {
|
|
1883
|
+
if (index < buffer.length) {
|
|
1884
|
+
expect = 'numberFraction';
|
|
1885
|
+
break;
|
|
1886
|
+
}
|
|
1887
|
+
if (done) {
|
|
1888
|
+
expect = expected[parent];
|
|
1889
|
+
break;
|
|
1890
|
+
}
|
|
1891
|
+
break main; // wait for more input
|
|
1892
|
+
}
|
|
1893
|
+
break;
|
|
1894
|
+
case 'numberFraction': // [\.eE]?
|
|
1895
|
+
patterns.numberFraction.lastIndex = index;
|
|
1896
|
+
match = patterns.numberFraction.exec(buffer);
|
|
1897
|
+
if (!match) {
|
|
1898
|
+
if (index < buffer.length || done) {
|
|
1899
|
+
expect = expected[parent];
|
|
1900
|
+
break;
|
|
1901
|
+
}
|
|
1902
|
+
break main; // wait for more input
|
|
1903
|
+
}
|
|
1904
|
+
value = match[0];
|
|
1905
|
+
if (streamNumbers) tokens.push({name: 'numberChunk', value});
|
|
1906
|
+
packNumbers && (accumulator += value);
|
|
1907
|
+
expect = value === '.' ? 'numberFracStart' : 'numberExpSign';
|
|
1908
|
+
index += value.length;
|
|
1909
|
+
break;
|
|
1910
|
+
case 'numberFracStart': // [0-9]
|
|
1911
|
+
patterns.numberFracStart.lastIndex = index;
|
|
1912
|
+
match = patterns.numberFracStart.exec(buffer);
|
|
1913
|
+
if (!match) {
|
|
1914
|
+
if (index < buffer.length || done) throw new Error('Parser cannot parse input: expected a fractional part of a number');
|
|
1915
|
+
break main; // wait for more input
|
|
1916
|
+
}
|
|
1917
|
+
value = match[0];
|
|
1918
|
+
if (streamNumbers) tokens.push({name: 'numberChunk', value});
|
|
1919
|
+
packNumbers && (accumulator += value);
|
|
1920
|
+
expect = 'numberFracDigit';
|
|
1921
|
+
index += value.length;
|
|
1922
|
+
break;
|
|
1923
|
+
case 'numberFracDigit': // [0-9]*
|
|
1924
|
+
patterns.numberFracDigit.lastIndex = index;
|
|
1925
|
+
match = patterns.numberFracDigit.exec(buffer);
|
|
1926
|
+
value = match[0];
|
|
1927
|
+
if (value) {
|
|
1928
|
+
if (streamNumbers) tokens.push({name: 'numberChunk', value});
|
|
1929
|
+
packNumbers && (accumulator += value);
|
|
1930
|
+
index += value.length;
|
|
1931
|
+
} else {
|
|
1932
|
+
if (index < buffer.length) {
|
|
1933
|
+
expect = 'numberExponent';
|
|
1934
|
+
break;
|
|
1935
|
+
}
|
|
1936
|
+
if (done) {
|
|
1937
|
+
expect = expected[parent];
|
|
1938
|
+
break;
|
|
1939
|
+
}
|
|
1940
|
+
break main; // wait for more input
|
|
1941
|
+
}
|
|
1942
|
+
break;
|
|
1943
|
+
case 'numberExponent': // [eE]?
|
|
1944
|
+
patterns.numberExponent.lastIndex = index;
|
|
1945
|
+
match = patterns.numberExponent.exec(buffer);
|
|
1946
|
+
if (!match) {
|
|
1947
|
+
if (index < buffer.length) {
|
|
1948
|
+
expect = expected[parent];
|
|
1949
|
+
break;
|
|
1950
|
+
}
|
|
1951
|
+
if (done) {
|
|
1952
|
+
expect = expected[parent];
|
|
1953
|
+
break;
|
|
1954
|
+
}
|
|
1955
|
+
break main; // wait for more input
|
|
1956
|
+
}
|
|
1957
|
+
value = match[0];
|
|
1958
|
+
if (streamNumbers) tokens.push({name: 'numberChunk', value});
|
|
1959
|
+
packNumbers && (accumulator += value);
|
|
1960
|
+
expect = 'numberExpSign';
|
|
1961
|
+
index += value.length;
|
|
1962
|
+
break;
|
|
1963
|
+
case 'numberExpSign': // [-+]?
|
|
1964
|
+
patterns.numberExpSign.lastIndex = index;
|
|
1965
|
+
match = patterns.numberExpSign.exec(buffer);
|
|
1966
|
+
if (!match) {
|
|
1967
|
+
if (index < buffer.length) {
|
|
1968
|
+
expect = 'numberExpStart';
|
|
1969
|
+
break;
|
|
1970
|
+
}
|
|
1971
|
+
if (done) throw new Error('Parser has expected an exponent value of a number');
|
|
1972
|
+
break main; // wait for more input
|
|
1973
|
+
}
|
|
1974
|
+
value = match[0];
|
|
1975
|
+
if (streamNumbers) tokens.push({name: 'numberChunk', value});
|
|
1976
|
+
packNumbers && (accumulator += value);
|
|
1977
|
+
expect = 'numberExpStart';
|
|
1978
|
+
index += value.length;
|
|
1979
|
+
break;
|
|
1980
|
+
case 'numberExpStart': // [0-9]
|
|
1981
|
+
patterns.numberExpStart.lastIndex = index;
|
|
1982
|
+
match = patterns.numberExpStart.exec(buffer);
|
|
1983
|
+
if (!match) {
|
|
1984
|
+
if (index < buffer.length || done) throw new Error('Parser cannot parse input: expected an exponent part of a number');
|
|
1985
|
+
break main; // wait for more input
|
|
1986
|
+
}
|
|
1987
|
+
value = match[0];
|
|
1988
|
+
if (streamNumbers) tokens.push({name: 'numberChunk', value});
|
|
1989
|
+
packNumbers && (accumulator += value);
|
|
1990
|
+
expect = 'numberExpDigit';
|
|
1991
|
+
index += value.length;
|
|
1992
|
+
break;
|
|
1993
|
+
case 'numberExpDigit': // [0-9]*
|
|
1994
|
+
patterns.numberExpDigit.lastIndex = index;
|
|
1995
|
+
match = patterns.numberExpDigit.exec(buffer);
|
|
1996
|
+
value = match[0];
|
|
1997
|
+
if (value) {
|
|
1998
|
+
if (streamNumbers) tokens.push({name: 'numberChunk', value});
|
|
1999
|
+
packNumbers && (accumulator += value);
|
|
2000
|
+
index += value.length;
|
|
2001
|
+
} else {
|
|
2002
|
+
if (index < buffer.length || done) {
|
|
2003
|
+
expect = expected[parent];
|
|
2004
|
+
break;
|
|
2005
|
+
}
|
|
2006
|
+
break main; // wait for more input
|
|
2007
|
+
}
|
|
2008
|
+
break;
|
|
2009
|
+
case 'done': {
|
|
2010
|
+
while (index < buffer.length) {
|
|
2011
|
+
cc = buffer.charCodeAt(index);
|
|
2012
|
+
if (cc === ASCII_SPACE || cc === ASCII_TAB || cc === ASCII_LF || cc === ASCII_CR) {
|
|
2013
|
+
if (openNumber) {
|
|
2014
|
+
if (streamNumbers) tokens.push(tokenEndNumber);
|
|
2015
|
+
openNumber = false;
|
|
2016
|
+
if (packNumbers) {
|
|
2017
|
+
tokens.push({name: 'numberValue', value: accumulator});
|
|
2018
|
+
accumulator = '';
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
++index;
|
|
2022
|
+
continue;
|
|
2023
|
+
}
|
|
2024
|
+
break;
|
|
2025
|
+
}
|
|
2026
|
+
if (index >= buffer.length) break main; // wait for more input / end
|
|
2027
|
+
if (jsonStreaming) {
|
|
2028
|
+
if (openNumber) {
|
|
2029
|
+
if (streamNumbers) tokens.push(tokenEndNumber);
|
|
2030
|
+
openNumber = false;
|
|
2031
|
+
if (packNumbers) {
|
|
2032
|
+
tokens.push({name: 'numberValue', value: accumulator});
|
|
2033
|
+
accumulator = '';
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
expect = 'value';
|
|
2037
|
+
continue main;
|
|
2038
|
+
}
|
|
2039
|
+
throw new Error('Parser cannot parse input: unexpected characters');
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
if (done && openNumber) {
|
|
2044
|
+
if (streamNumbers) tokens.push(tokenEndNumber);
|
|
2045
|
+
openNumber = false;
|
|
2046
|
+
if (packNumbers) {
|
|
2047
|
+
tokens.push({name: 'numberValue', value: accumulator});
|
|
2048
|
+
accumulator = '';
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
buffer = buffer.slice(index);
|
|
2052
|
+
return tokens.length ? many(tokens) : none;
|
|
2053
|
+
});
|
|
2054
|
+
};
|
|
2055
|
+
|
|
2056
|
+
const parser = options => gen(fixUtf8Stream(), jsonParser(options));
|
|
2057
|
+
|
|
2058
|
+
parser.parser = parser; // for backward compatibility with 1.x
|
|
2059
|
+
|
|
2060
|
+
// @ts-self-types="./parser.d.ts"
|
|
2061
|
+
|
|
2062
|
+
|
|
2063
|
+
/** @type {any} */ (parser).asStream = options => asStream(parser(options), {writableObjectMode: true, readableObjectMode: true, ...options});
|
|
2064
|
+
/** @type {any} */ (parser).asWebStream = options => asWebStream(parser(options), {...options});
|
|
2065
|
+
|
|
2066
|
+
// @ts-self-types="./index.d.ts"
|
|
2067
|
+
|
|
2068
|
+
|
|
2069
|
+
parser.asStream;
|
|
2070
|
+
|
|
2071
|
+
// @ts-self-types="./assembler.d.ts"
|
|
2072
|
+
|
|
2073
|
+
|
|
2074
|
+
const startObject = Ctr =>
|
|
2075
|
+
/** @this {Assembler} */
|
|
2076
|
+
function () {
|
|
2077
|
+
if (this.done) {
|
|
2078
|
+
this.done = false;
|
|
2079
|
+
} else {
|
|
2080
|
+
this.stack.push(this.current, this.key);
|
|
2081
|
+
}
|
|
2082
|
+
this.current = new Ctr();
|
|
2083
|
+
this.key = null;
|
|
2084
|
+
};
|
|
2085
|
+
|
|
2086
|
+
class Assembler {
|
|
2087
|
+
static connectTo(stream, options) {
|
|
2088
|
+
return new Assembler(options).connectTo(stream);
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
constructor(options) {
|
|
2092
|
+
this.stack = [];
|
|
2093
|
+
this.current = this.key = null;
|
|
2094
|
+
this.done = true;
|
|
2095
|
+
this._onDone = null;
|
|
2096
|
+
if (options) {
|
|
2097
|
+
this.reviver = typeof options.reviver == 'function' && options.reviver;
|
|
2098
|
+
if (this.reviver) {
|
|
2099
|
+
this.stringValue = this._saveValue = this._saveValueWithReviver;
|
|
2100
|
+
}
|
|
2101
|
+
if (options.numberAsString) {
|
|
2102
|
+
this.numberValue = this.stringValue;
|
|
2103
|
+
}
|
|
2104
|
+
if (typeof options.onDone == 'function') {
|
|
2105
|
+
this._onDone = options.onDone;
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
this.tapChain = chunk => {
|
|
2110
|
+
if (this[chunk.name]) {
|
|
2111
|
+
this[chunk.name](chunk.value);
|
|
2112
|
+
if (this.done) return this.current;
|
|
2113
|
+
}
|
|
2114
|
+
return none;
|
|
2115
|
+
};
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
connectTo(stream) {
|
|
2119
|
+
const consume = chunk => {
|
|
2120
|
+
if (this[chunk.name]) {
|
|
2121
|
+
this[chunk.name](chunk.value);
|
|
2122
|
+
if (this.done) this._onDone?.(this);
|
|
2123
|
+
}
|
|
2124
|
+
};
|
|
2125
|
+
if (typeof stream?.getReader === 'function') {
|
|
2126
|
+
const reader = stream.getReader();
|
|
2127
|
+
(async () => {
|
|
2128
|
+
try {
|
|
2129
|
+
for (;;) {
|
|
2130
|
+
const {done, value} = await reader.read();
|
|
2131
|
+
if (done) return;
|
|
2132
|
+
consume(value);
|
|
2133
|
+
}
|
|
2134
|
+
} finally {
|
|
2135
|
+
reader.releaseLock();
|
|
2136
|
+
}
|
|
2137
|
+
})();
|
|
2138
|
+
} else {
|
|
2139
|
+
stream.on('data', consume);
|
|
2140
|
+
}
|
|
2141
|
+
return this;
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
onDone(fn) {
|
|
2145
|
+
this._onDone = typeof fn == 'function' ? fn : null;
|
|
2146
|
+
return this;
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
get depth() {
|
|
2150
|
+
return (this.stack.length >> 1) + (this.done ? 0 : 1);
|
|
2151
|
+
}
|
|
2152
|
+
|
|
2153
|
+
get path() {
|
|
2154
|
+
const path = [];
|
|
2155
|
+
for (let i = 0; i < this.stack.length; i += 2) {
|
|
2156
|
+
const key = this.stack[i + 1];
|
|
2157
|
+
path.push(key === null ? this.stack[i].length : key);
|
|
2158
|
+
}
|
|
2159
|
+
return path;
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
dropToLevel(level) {
|
|
2163
|
+
if (level < this.depth) {
|
|
2164
|
+
if (level > 0) {
|
|
2165
|
+
const index = (level - 1) << 1;
|
|
2166
|
+
this.current = this.stack[index];
|
|
2167
|
+
this.key = this.stack[index + 1];
|
|
2168
|
+
this.stack.splice(index);
|
|
2169
|
+
} else {
|
|
2170
|
+
this.stack = [];
|
|
2171
|
+
this.current = this.key = null;
|
|
2172
|
+
this.done = true;
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
return this;
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
consume(chunk) {
|
|
2179
|
+
this[chunk.name]?.(chunk.value);
|
|
2180
|
+
return this;
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
keyValue(value) {
|
|
2184
|
+
this.key = value;
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
//stringValue() - aliased below to _saveValue()
|
|
2188
|
+
|
|
2189
|
+
numberValue(value) {
|
|
2190
|
+
this._saveValue(parseFloat(value));
|
|
2191
|
+
}
|
|
2192
|
+
nullValue() {
|
|
2193
|
+
this._saveValue(null);
|
|
2194
|
+
}
|
|
2195
|
+
trueValue() {
|
|
2196
|
+
this._saveValue(true);
|
|
2197
|
+
}
|
|
2198
|
+
falseValue() {
|
|
2199
|
+
this._saveValue(false);
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
//startObject() - assigned below
|
|
2203
|
+
|
|
2204
|
+
endObject() {
|
|
2205
|
+
if (this.stack.length) {
|
|
2206
|
+
const value = this.current;
|
|
2207
|
+
this.key = this.stack.pop();
|
|
2208
|
+
this.current = this.stack.pop();
|
|
2209
|
+
this._saveValue(value);
|
|
2210
|
+
} else {
|
|
2211
|
+
if (this.reviver) {
|
|
2212
|
+
this.current = this.reviver.call({'': this.current}, '', this.current);
|
|
2213
|
+
}
|
|
2214
|
+
this.done = true;
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
//startArray() - assigned below
|
|
2219
|
+
//endArray() - aliased below to endObject()
|
|
2220
|
+
|
|
2221
|
+
_saveValue(value) {
|
|
2222
|
+
if (this.done) {
|
|
2223
|
+
this.current = value;
|
|
2224
|
+
return;
|
|
2225
|
+
}
|
|
2226
|
+
if (this.current instanceof Array) {
|
|
2227
|
+
this.current.push(value);
|
|
2228
|
+
} else {
|
|
2229
|
+
this.current[this.key] = value;
|
|
2230
|
+
this.key = null;
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
_saveValueWithReviver(value) {
|
|
2234
|
+
if (this.done) {
|
|
2235
|
+
this.current = this.reviver.call({'': value}, '', value);
|
|
2236
|
+
return;
|
|
2237
|
+
}
|
|
2238
|
+
if (this.current instanceof Array) {
|
|
2239
|
+
this.current.push(value);
|
|
2240
|
+
value = this.reviver.call(this.current, String(this.current.length - 1), value);
|
|
2241
|
+
if (value === undefined) {
|
|
2242
|
+
delete this.current[this.current.length - 1];
|
|
2243
|
+
} else {
|
|
2244
|
+
this.current[this.current.length - 1] = value;
|
|
2245
|
+
}
|
|
2246
|
+
} else {
|
|
2247
|
+
value = this.reviver.call(this.current, this.key, value);
|
|
2248
|
+
if (value !== undefined) {
|
|
2249
|
+
this.current[this.key] = value;
|
|
2250
|
+
}
|
|
2251
|
+
this.key = null;
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
1611
2254
|
}
|
|
1612
2255
|
|
|
1613
|
-
|
|
1614
|
-
|
|
2256
|
+
Assembler.prototype.stringValue = Assembler.prototype._saveValue;
|
|
2257
|
+
Assembler.prototype.startObject = startObject(Object);
|
|
2258
|
+
Assembler.prototype.startArray = startObject(Array);
|
|
2259
|
+
Assembler.prototype.endArray = Assembler.prototype.endObject;
|
|
2260
|
+
|
|
2261
|
+
const assembler = options => new Assembler(options);
|
|
2262
|
+
Assembler.assembler = assembler;
|
|
1615
2263
|
|
|
1616
2264
|
class JsonParseStreamError extends Error {
|
|
1617
2265
|
constructor(message, data) {
|
|
@@ -1621,25 +2269,25 @@ class JsonParseStreamError extends Error {
|
|
|
1621
2269
|
}
|
|
1622
2270
|
function parseJsonStream(stream) {
|
|
1623
2271
|
const assembler = new Assembler();
|
|
1624
|
-
const parser =
|
|
2272
|
+
const parser$1 = parser.asStream();
|
|
1625
2273
|
return new Promise((resolve) => {
|
|
1626
|
-
parser.on("data", (chunk) => {
|
|
2274
|
+
parser$1.on("data", (chunk) => {
|
|
1627
2275
|
assembler[chunk.name]?.(chunk.value);
|
|
1628
2276
|
});
|
|
1629
|
-
stream.pipe(parser);
|
|
1630
|
-
parser.on("end", () => {
|
|
2277
|
+
stream.pipe(parser$1);
|
|
2278
|
+
parser$1.on("end", () => {
|
|
1631
2279
|
resolve(assembler.current);
|
|
1632
2280
|
});
|
|
1633
2281
|
});
|
|
1634
2282
|
}
|
|
1635
2283
|
function parseJsonStreamWithConcatArrays(stream, sourceName) {
|
|
1636
2284
|
const assembler = new Assembler();
|
|
1637
|
-
const parser =
|
|
2285
|
+
const parser$1 = parser.asStream({
|
|
1638
2286
|
jsonStreaming: true
|
|
1639
2287
|
});
|
|
1640
2288
|
const values = [];
|
|
1641
2289
|
return new Promise((resolve) => {
|
|
1642
|
-
parser.on("data", (chunk) => {
|
|
2290
|
+
parser$1.on("data", (chunk) => {
|
|
1643
2291
|
assembler[chunk.name]?.(chunk.value);
|
|
1644
2292
|
if (assembler.done) {
|
|
1645
2293
|
if (!Array.isArray(assembler.current)) {
|
|
@@ -1650,8 +2298,8 @@ function parseJsonStreamWithConcatArrays(stream, sourceName) {
|
|
|
1650
2298
|
values.push(...assembler.current);
|
|
1651
2299
|
}
|
|
1652
2300
|
});
|
|
1653
|
-
stream.pipe(parser);
|
|
1654
|
-
parser.on("end", () => {
|
|
2301
|
+
stream.pipe(parser$1);
|
|
2302
|
+
parser$1.on("end", () => {
|
|
1655
2303
|
resolve(values);
|
|
1656
2304
|
});
|
|
1657
2305
|
});
|