Skip to content

Commit

Permalink
fix: Don't exit synchronously when there still might be async I/O (#90)
Browse files Browse the repository at this point in the history
See https://nodejs.org/api/process.html#processexitcode for an
explanation of process.exit and process.exitCode and
https://nodejs.org/api/process.html#a-note-on-process-io for an
explanation when I/O might be sync or async.

Additionally writes a newline after format "json" has been written. This
prevents strange behavior in at least zsh when output is not terminated
by a newline.
  • Loading branch information
codeworrior authored Apr 23, 2024
1 parent 9720b61 commit fd9b7b9
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 6 deletions.
3 changes: 2 additions & 1 deletion src/cli/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ async function handleLint(argv: ArgumentsCamelCase<LinterArg>) {
if (format === "json") {
const jsonFormatter = new Json();
process.stdout.write(jsonFormatter.format(res, details));
process.stdout.write("\n");
} else if (format === "" || format === "stylish") {
const textFormatter = new Text();
process.stderr.write(textFormatter.format(res, details));
Expand All @@ -144,7 +145,7 @@ async function handleLint(argv: ArgumentsCamelCase<LinterArg>) {

if (res.some((file) => !!file.errorCount)) {
// At least one error is reported. Exit with non-zero exit code.
process.exit(1);
process.exitCode = 1;
}
}

Expand Down
16 changes: 11 additions & 5 deletions test/lib/cli/base.integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,20 @@ test.serial("ui5lint --format json", async (t) => {

t.is(consoleLogStub.callCount, 0, "console.log should not be used");
t.true(processCwdStub.callCount > 0, "process.cwd was called");
t.is(processStdoutWriteStub.callCount, 1, "process.stdout.write is only used once");
t.is(processExitStub.callCount, 1, "process.exit got called once");
t.is(processExitStub.firstCall.firstArg, 1, "process.exit got called with exit code 1");
t.is(processStdoutWriteStub.callCount, 2, "process.stdout.write was called twice");
t.is(processExitStub.callCount, 0, "process.exit got never called");
t.is(process.exitCode, 1, "process.exitCode was set to 1");
// cleanup: reset exit code in order not to fail the test (it cannot be stubbed with sinon)
process.exitCode = 0;

const resultProcessStdout = processStdoutWriteStub.firstCall.firstArg;
const resultProcessStdoutJSON = processStdoutWriteStub.firstCall.firstArg;
let parsedJson: LintResult[];

t.notThrows(() => parsedJson = JSON.parse(resultProcessStdout), "Output of process.stdout.write is JSON-formatted");
t.notThrows(() => parsedJson = JSON.parse(resultProcessStdoutJSON),
"Output of process.stdout.write is JSON-formatted");
t.true(Array.isArray(parsedJson!), "The parsed JSON output is a LintResult array");
t.true(parsedJson!.length > 0, "The parsed JSON output contains at least one result");

const resultProcessStdoutNL = processStdoutWriteStub.secondCall.firstArg;
t.is(resultProcessStdoutNL, "\n", "second write only adds a single newline");
});

0 comments on commit fd9b7b9

Please sign in to comment.