vectorjson 0.2.1 → 0.3.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/README.md CHANGED
@@ -308,6 +308,73 @@ parser.onText((text) => thinkingPanel.append(text)); // opt-in
308
308
  parser.feed(llmOutput);
309
309
  ```
310
310
 
311
+ ### Field picking — only parse what you need
312
+
313
+ When streaming a large tool call, you often only need 2-3 fields. `pick` tells the parser to skip everything else during byte scanning — skipped fields never allocate JS objects:
314
+
315
+ ```js
316
+ import { createParser } from "vectorjson";
317
+
318
+ const parser = createParser({ pick: ["name", "age"] });
319
+ parser.feed('{"name":"Alice","age":30,"bio":"...10KB of text...","metadata":{}}');
320
+ parser.getValue(); // { name: "Alice", age: 30 } — bio and metadata never materialized
321
+ parser.destroy();
322
+ ```
323
+
324
+ Nested paths work with dot notation:
325
+
326
+ ```js
327
+ const parser = createParser({ pick: ["user.name", "user.age"] });
328
+ parser.feed('{"user":{"name":"Bob","age":25,"role":"admin"},"extra":"data"}');
329
+ parser.getValue(); // { user: { name: "Bob", age: 25 } }
330
+ parser.destroy();
331
+ ```
332
+
333
+ ### `for await` — pull-based streaming from any source
334
+
335
+ Pass a `source` (ReadableStream or AsyncIterable) and iterate with `for await`. Each iteration yields the growing partial value:
336
+
337
+ ```js
338
+ import { createParser } from "vectorjson";
339
+
340
+ const parser = createParser({ source: response.body });
341
+
342
+ for await (const partial of parser) {
343
+ console.log(partial);
344
+ // { name: "Ali" }
345
+ // { name: "Alice" }
346
+ // { name: "Alice", age: 30 }
347
+ }
348
+ // Parser auto-destroys when the source ends or you break out of the loop
349
+ ```
350
+
351
+ Combine `pick` + `source` for minimal allocation streaming:
352
+
353
+ ```js
354
+ const parser = createParser({
355
+ pick: ["name", "age"],
356
+ source: response.body,
357
+ });
358
+
359
+ for await (const partial of parser) {
360
+ updateUI(partial); // only picked fields, growing incrementally
361
+ }
362
+ ```
363
+
364
+ Works with any async source — fetch body, WebSocket wrapper, SSE adapter, or a plain async generator:
365
+
366
+ ```js
367
+ async function* chunks() {
368
+ yield '{"status":"';
369
+ yield 'ok","data":';
370
+ yield '[1,2,3]}';
371
+ }
372
+
373
+ for await (const partial of createParser({ source: chunks() })) {
374
+ console.log(partial);
375
+ }
376
+ ```
377
+
311
378
  ### Schema validation
312
379
 
313
380
  Validate and auto-infer types with Zod, Valibot, ArkType, or any lib with `.safeParse()`. Works on all three APIs:
@@ -449,8 +516,33 @@ interface ParseResult {
449
516
  - **`invalid`** — broken JSON
450
517
 
451
518
  ### `createParser(schema?): StreamingParser<T>`
519
+ ### `createParser(options?): StreamingParser<T>`
520
+
521
+ Each `feed()` processes only new bytes — O(n) total. Three overloads:
522
+
523
+ ```ts
524
+ createParser(); // no validation
525
+ createParser(schema); // schema validation (Zod, Valibot, etc.)
526
+ createParser({ pick, schema, source }); // options object
527
+ ```
452
528
 
453
- Each `feed()` processes only new bytes — O(n) total. Pass an optional schema to auto-validate and infer the return type.
529
+ **Options object:**
530
+
531
+ ```ts
532
+ interface CreateParserOptions<T = unknown> {
533
+ pick?: string[]; // only include these fields (dot-separated paths)
534
+ schema?: ZodLike<T>; // validate on complete
535
+ source?: ReadableStream<Uint8Array> | AsyncIterable<Uint8Array | string>;
536
+ }
537
+ ```
538
+
539
+ When `source` is provided, the parser becomes async-iterable — use `for await` to consume partial values:
540
+
541
+ ```ts
542
+ for await (const partial of createParser({ source: stream, pick: ["name"] })) {
543
+ console.log(partial); // growing object with only picked fields
544
+ }
545
+ ```
454
546
 
455
547
  ```ts
456
548
  interface StreamingParser<T = unknown> {
@@ -460,6 +552,7 @@ interface StreamingParser<T = unknown> {
460
552
  getRawBuffer(): ArrayBuffer | null; // transferable buffer for Worker postMessage
461
553
  getStatus(): FeedStatus;
462
554
  destroy(): void;
555
+ [Symbol.asyncIterator](): AsyncIterableIterator<T | undefined>; // requires source
463
556
  }
464
557
  type FeedStatus = "incomplete" | "complete" | "error" | "end_early";
465
558
  ```
@@ -644,6 +737,13 @@ node --expose-gc bench/deep-compare.mjs # deep compare: VJ vs JS deepEq
644
737
 
645
738
  Benchmark numbers in this README were measured on GitHub Actions (Ubuntu, x86_64). Results vary by machine but relative speedups are consistent.
646
739
 
740
+ ## Acknowledgments
741
+
742
+ VectorJSON is built on the work of:
743
+
744
+ - **[zimdjson](https://github.com/EzequielRamis/zimdjson)** by Ezequiel Ramis — a Zig port of simdjson that powers the WASM engine
745
+ - **[simdjson](https://simdjson.org/)** by Daniel Lemire & Geoff Langdale — the SIMD-accelerated JSON parsing research that started it all
746
+
647
747
  ## License
648
748
 
649
749
  Apache-2.0