Skip to content

Commit 2950f9b

Browse files
authored
Merge pull request #227 from arethetypeswrong/bug/184
Fix truncated stdout when piping more than 64kb
2 parents 1f3381f + 55544ac commit 2950f9b

File tree

4 files changed

+48
-8
lines changed

4 files changed

+48
-8
lines changed

.changeset/polite-gifts-judge.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@arethetypeswrong/cli": patch
3+
---
4+
5+
Fix truncated stdout when piping more than 64kb to another process

packages/cli/src/index.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import * as render from "./render/index.js";
1616
import { major, minor } from "semver";
1717
import { getExitCode } from "./getExitCode.js";
1818
import { applyProfile, profiles } from "./profiles.js";
19+
import { write } from "./write.js";
20+
import { Writable } from "stream";
1921

2022
const packageJson = createRequire(import.meta.url)("../package.json");
2123
const version = packageJson.version;
@@ -98,8 +100,13 @@ particularly ESM-related module resolution issues.`,
98100
applyProfile(opts.profile, opts);
99101
}
100102

103+
let out: Writable = process.stdout;
101104
if (opts.quiet) {
102-
console.log = () => {};
105+
out = new (class extends Writable {
106+
_write(_chunk: any, _encoding: BufferEncoding, callback: (error?: Error | null) => void) {
107+
callback();
108+
}
109+
})();
103110
}
104111

105112
if (!opts.color) {
@@ -223,7 +230,7 @@ particularly ESM-related module resolution issues.`,
223230
result.problems = groupProblemsByKind(analysis.problems);
224231
}
225232

226-
console.log(JSON.stringify(result, undefined, 2));
233+
await write(JSON.stringify(result, undefined, 2), out);
227234

228235
if (deleteTgz) {
229236
await unlink(deleteTgz);
@@ -237,12 +244,12 @@ particularly ESM-related module resolution issues.`,
237244
return;
238245
}
239246

240-
console.log();
247+
await write("", out);
241248
if (analysis.types) {
242-
console.log(await render.typed(analysis, opts));
249+
await write(await render.typed(analysis, opts), out);
243250
process.exitCode = getExitCode(analysis, opts);
244251
} else {
245-
console.log(render.untyped(analysis as core.UntypedResult));
252+
await write(render.untyped(analysis as core.UntypedResult), out);
246253
}
247254

248255
if (deleteTgz) {

packages/cli/src/write.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Readable, Writable } from "node:stream";
2+
3+
// JSON output is often longer than 64 kb, so we need to use streams to write it to stdout
4+
// in order to avoid truncation when piping to other commands.
5+
export async function write(data: string, out: Writable): Promise<void> {
6+
return new Promise((resolve, reject) => {
7+
const stream = new Readable({
8+
read() {
9+
this.push(data);
10+
this.push("\n");
11+
this.push(null);
12+
},
13+
});
14+
15+
stream.on("data", (chunk) => {
16+
out.write(chunk);
17+
});
18+
19+
stream.on("end", () => {
20+
resolve();
21+
});
22+
23+
out.on("error", (err) => {
24+
reject(err);
25+
});
26+
});
27+
}

packages/cli/test/snapshots.test.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import { execFileSync, type SpawnSyncReturns } from "child_process";
12
import { access, readFile, writeFile } from "fs/promises";
2-
import { execSync, type SpawnSyncReturns } from "child_process";
33
import assert from "node:assert";
44
import path from "node:path";
55
import { after, describe, test } from "node:test";
@@ -10,7 +10,7 @@ function resolveFileRelativePath(relPath: string) {
1010
return path.resolve(directoryPath, relPath);
1111
}
1212

13-
const attw = `node ${resolveFileRelativePath("../../dist/index.js")}`;
13+
const attw = resolveFileRelativePath("../../dist/index.js");
1414
const updateSnapshots = process.env.UPDATE_SNAPSHOTS || process.env.U;
1515
const testFilter = (process.env.TEST_FILTER || process.env.T)?.toLowerCase();
1616

@@ -91,7 +91,8 @@ describe("snapshots", async () => {
9191
let stderr = "";
9292
let exitCode = 0;
9393
try {
94-
stdout = execSync(`${attw} ${tarballPath} ${options ?? defaultOpts}`, {
94+
stdout = execFileSync(process.execPath, [attw, tarballPath, ...(options ?? defaultOpts).split(" ")], {
95+
maxBuffer: 1024 * 1024 * 1024,
9596
encoding: "utf8",
9697
env: { ...process.env, FORCE_COLOR: "0" },
9798
});

0 commit comments

Comments
 (0)