diff --git a/packages/csv-stringify/lib/index.js b/packages/csv-stringify/lib/index.js index 00ca12654..b4c686b00 100644 --- a/packages/csv-stringify/lib/index.js +++ b/packages/csv-stringify/lib/index.js @@ -87,8 +87,9 @@ const stringify = function () { callback(err); }); stringifier.on("end", function () { + let data; try { - callback(undefined, chunks.join("")); + data = chunks.join(""); } catch (err) { // This can happen if the `chunks` is extremely long; it may throw // "Cannot create a string longer than 0x1fffffe8 characters" @@ -96,6 +97,7 @@ const stringify = function () { callback(err); return; } + callback(undefined, data); }); } if (data !== undefined) { diff --git a/packages/csv-stringify/test/api.callback.js b/packages/csv-stringify/test/api.callback.js index 68133a580..2c88ae18d 100644 --- a/packages/csv-stringify/test/api.callback.js +++ b/packages/csv-stringify/test/api.callback.js @@ -1,4 +1,6 @@ import "should"; +import assert from "node:assert/strict"; +import { spawnSync } from "node:child_process"; import { stringify } from "../lib/index.js"; describe("api.callback", function () { @@ -39,6 +41,36 @@ describe("api.callback", function () { ); }); + it("does not invoke a throwing callback twice", function () { + const result = spawnSync( + process.execPath, + [ + "--input-type=module", + "--eval", + ` + import assert from "node:assert/strict"; + import { stringify } from ${JSON.stringify(new URL("../lib/index.js", import.meta.url).href)}; + + const error = new Error("Callback failed"); + let calls = 0; + let caught = false; + process.once("uncaughtException", (err) => { + assert.equal(err, error); + assert.equal(calls, 1); + caught = true; + }); + process.on("exit", () => assert.equal(caught, true)); + stringify([["value"]], () => { + calls++; + throw error; + }); + `, + ], + { encoding: "utf8" }, + ); + assert.equal(result.status, 0, result.stderr); + }); + it("catch error in end handler, see #386", function (next) { const input = Array.from({ length: 200000 }).map(() => Array.from({ length: 100 }).map(