diff --git a/.changeset/tough-rooms-camp.md b/.changeset/tough-rooms-camp.md new file mode 100644 index 00000000000..26ae61b4f83 --- /dev/null +++ b/.changeset/tough-rooms-camp.md @@ -0,0 +1,5 @@ +--- +"effect": patch +--- + +Reject NDJSON values without a JSON representation. diff --git a/packages/effect/src/unstable/encoding/Ndjson.ts b/packages/effect/src/unstable/encoding/Ndjson.ts index 87bcce19746..ce9e33b424f 100644 --- a/packages/effect/src/unstable/encoding/Ndjson.ts +++ b/packages/effect/src/unstable/encoding/Ndjson.ts @@ -73,7 +73,15 @@ export const encodeString = (): Channel.Channel< Channel.fromTransform((upstream, _scope) => Effect.succeed(Effect.flatMap(upstream, (input) => { try { - return Effect.succeed(Arr.of(input.map((item) => JSON.stringify(item)).join("\n") + "\n")) + return Effect.succeed(Arr.of( + input.map((item) => { + const output = JSON.stringify(item) + if (output === undefined) { + throw new TypeError("Value cannot be represented as JSON") + } + return output + }).join("\n") + "\n" + )) } catch (cause) { return Effect.fail(new NdjsonError({ kind: "Pack", cause })) } diff --git a/packages/effect/test/unstable/encoding/Ndjson.test.ts b/packages/effect/test/unstable/encoding/Ndjson.test.ts index 4e1f06d558e..fbc0b10ce36 100644 --- a/packages/effect/test/unstable/encoding/Ndjson.test.ts +++ b/packages/effect/test/unstable/encoding/Ndjson.test.ts @@ -4,6 +4,22 @@ import * as Schema from "effect/Schema" import * as Ndjson from "effect/unstable/encoding/Ndjson" describe("Ndjson", () => { + it.effect("fails for values without a JSON representation", () => + Effect.gen(function*() { + const inputs = [undefined, () => {}, Symbol("x")] + + for (const input of inputs) { + const error = yield* Stream.make(input).pipe( + Stream.pipeThroughChannel(Ndjson.encodeString()), + Stream.runCollect, + Effect.flip + ) + + assert.instanceOf(error, Ndjson.NdjsonError) + assert.strictEqual(error.kind, "Pack") + } + })) + it.effect("decodeSchema decodes records split across Uint8Array chunks", () => Effect.gen(function*() { const messages = yield* Stream.make(