2024-01-01 21:11:32 +00:00
|
|
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
2023-03-18 12:36:00 +00:00
|
|
|
// This module is browser compatible.
|
|
|
|
|
2024-06-21 05:56:11 +00:00
|
|
|
import type { JsonValue } from "./types.ts";
|
2023-03-13 05:56:53 +00:00
|
|
|
import { parse } from "./_common.ts";
|
|
|
|
|
2024-10-10 11:09:15 +00:00
|
|
|
const blanks = /^[ \t\r\n]*$/;
|
|
|
|
function isBlankSpace(str: string) {
|
|
|
|
return blanks.test(str);
|
2023-03-13 05:56:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse each chunk as JSON.
|
|
|
|
*
|
2024-05-20 07:14:09 +00:00
|
|
|
* This can be used to parse {@link https://jsonlines.org/ | JSON lines},
|
|
|
|
* {@link http://ndjson.org/ | NDJSON} and
|
|
|
|
* {@link https://www.rfc-editor.org/rfc/rfc7464.html | JSON Text Sequences}.
|
2023-03-13 05:56:53 +00:00
|
|
|
* Chunks consisting of spaces, tab characters, or newline characters will be ignored.
|
|
|
|
*
|
2024-06-18 10:10:57 +00:00
|
|
|
* @example Basic usage
|
|
|
|
*
|
2023-03-13 05:56:53 +00:00
|
|
|
* ```ts
|
2024-07-02 01:57:00 +00:00
|
|
|
* import { JsonParseStream } from "@std/json/parse-stream";
|
refactor(assert,async,bytes,cli,collections,crypto,csv,data-structures,datetime,dotenv,encoding,expect,fmt,front-matter,fs,html,http,ini,internal,io,json,jsonc,log,media-types,msgpack,net,path,semver,streams,testing,text,toml,ulid,url,uuid,webgpu,yaml): import from `@std/assert` (#5199)
* refactor: import from `@std/assert`
* update
2024-06-30 08:30:10 +00:00
|
|
|
* import { assertEquals } from "@std/assert";
|
2023-03-13 05:56:53 +00:00
|
|
|
*
|
2024-06-18 10:10:57 +00:00
|
|
|
* const stream = ReadableStream.from([
|
|
|
|
* `{"foo":"bar"}\n`,
|
|
|
|
* `{"baz":100}\n`
|
|
|
|
* ]).pipeThrough(new JsonParseStream());
|
2023-03-13 05:56:53 +00:00
|
|
|
*
|
2024-06-18 10:10:57 +00:00
|
|
|
* assertEquals(await Array.fromAsync(stream), [
|
|
|
|
* { foo: "bar" },
|
|
|
|
* { baz: 100 }
|
|
|
|
* ]);
|
2023-03-13 05:56:53 +00:00
|
|
|
* ```
|
|
|
|
*
|
2024-06-18 10:10:57 +00:00
|
|
|
* @example parse JSON lines or NDJSON from a file
|
2023-03-13 05:56:53 +00:00
|
|
|
* ```ts
|
2024-06-18 10:10:57 +00:00
|
|
|
* import { TextLineStream } from "@std/streams/text-line-stream";
|
2024-07-02 01:57:00 +00:00
|
|
|
* import { JsonParseStream } from "@std/json/parse-stream";
|
refactor(assert,async,bytes,cli,collections,crypto,csv,data-structures,datetime,dotenv,encoding,expect,fmt,front-matter,fs,html,http,ini,internal,io,json,jsonc,log,media-types,msgpack,net,path,semver,streams,testing,text,toml,ulid,url,uuid,webgpu,yaml): import from `@std/assert` (#5199)
* refactor: import from `@std/assert`
* update
2024-06-30 08:30:10 +00:00
|
|
|
* import { assertEquals } from "@std/assert";
|
2023-03-13 05:56:53 +00:00
|
|
|
*
|
2024-06-18 10:10:57 +00:00
|
|
|
* const file = await Deno.open("json/testdata/test.jsonl");
|
2023-03-13 05:56:53 +00:00
|
|
|
*
|
2024-06-18 10:10:57 +00:00
|
|
|
* const readable = file.readable
|
|
|
|
* .pipeThrough(new TextDecoderStream()) // convert Uint8Array to string
|
|
|
|
* .pipeThrough(new TextLineStream()) // transform into a stream where each chunk is divided by a newline
|
|
|
|
* .pipeThrough(new JsonParseStream()); // parse each chunk as JSON
|
2023-03-13 05:56:53 +00:00
|
|
|
*
|
2024-06-18 10:10:57 +00:00
|
|
|
* assertEquals(await Array.fromAsync(readable), [
|
|
|
|
* {"hello": "world"},
|
|
|
|
* ["👋", "👋", "👋"],
|
|
|
|
* {"deno": "🦕"},
|
|
|
|
* ]);
|
2023-03-13 05:56:53 +00:00
|
|
|
* ```
|
|
|
|
*/
|
|
|
|
export class JsonParseStream extends TransformStream<string, JsonValue> {
|
2024-06-18 10:10:57 +00:00
|
|
|
/**
|
|
|
|
* Constructs new instance.
|
|
|
|
*/
|
2024-06-21 04:20:36 +00:00
|
|
|
constructor() {
|
2023-03-13 05:56:53 +00:00
|
|
|
super(
|
|
|
|
{
|
|
|
|
transform(chunk, controller) {
|
2024-10-10 11:09:15 +00:00
|
|
|
if (!isBlankSpace(chunk)) {
|
2023-03-13 05:56:53 +00:00
|
|
|
controller.enqueue(parse(chunk));
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|