Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/$.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,7 @@ let globalShellSettings = {
function createResult({ code, stdout = '', stderr = '', stdin = '' }) {
return {
code,
exitCode: code,
stdout,
stderr,
stdin,
Expand Down Expand Up @@ -2053,6 +2054,7 @@ class ProcessRunner extends StreamEmitter {

const resultData = {
code: finalExitCode,
exitCode: finalExitCode,
stdout: this.options.capture ? (this.outChunks && this.outChunks.length > 0 ? Buffer.concat(this.outChunks).toString('utf8') : '') : undefined,
stderr: this.options.capture ? (this.errChunks && this.errChunks.length > 0 ? Buffer.concat(this.errChunks).toString('utf8') : '') : undefined,
stdin: this.options.capture && this.inChunks ? Buffer.concat(this.inChunks).toString('utf8') : undefined,
Expand Down Expand Up @@ -2443,6 +2445,7 @@ class ProcessRunner extends StreamEmitter {

result = {
code: 0,
exitCode: 0,
stdout: this.options.capture ? Buffer.concat(chunks).toString('utf8') : undefined,
stderr: this.options.capture ? '' : undefined,
stdin: this.options.capture ? stdinData : undefined
Expand Down Expand Up @@ -2494,6 +2497,7 @@ class ProcessRunner extends StreamEmitter {
trace('ProcessRunner', () => `Virtual command cancelled with signal ${this._cancellationSignal}, exit code: ${exitCode}`);
result = {
code: exitCode,
exitCode: exitCode,
stdout: '',
stderr: ''
};
Expand All @@ -2505,6 +2509,7 @@ class ProcessRunner extends StreamEmitter {
result = {
...result,
code: result.code ?? 0,
exitCode: result.code ?? 0,
stdout: this.options.capture ? (result.stdout ?? '') : undefined,
stderr: this.options.capture ? (result.stderr ?? '') : undefined,
stdin: this.options.capture ? stdinData : undefined
Expand Down Expand Up @@ -2553,6 +2558,7 @@ class ProcessRunner extends StreamEmitter {

const result = {
code: exitCode,
exitCode: exitCode,
stdout: error.stdout ?? '',
stderr: error.stderr ?? error.message,
stdin: ''
Expand Down Expand Up @@ -3217,6 +3223,7 @@ class ProcessRunner extends StreamEmitter {
}
result = {
code: 0,
exitCode: 0,
stdout: this.options.capture ? Buffer.concat(chunks).toString('utf8') : undefined,
stderr: this.options.capture ? '' : undefined,
stdin: this.options.capture ? currentInput : undefined
Expand Down Expand Up @@ -3472,6 +3479,7 @@ class ProcessRunner extends StreamEmitter {

let result = {
code: proc.status || 0,
exitCode: proc.status || 0,
stdout: proc.stdout || '',
stderr: proc.stderr || '',
stdin: currentInput
Expand Down Expand Up @@ -3647,7 +3655,7 @@ class ProcessRunner extends StreamEmitter {
operators: sequence.operators
}, null, 2)}`);

let lastResult = { code: 0, stdout: '', stderr: '' };
let lastResult = { code: 0, exitCode: 0, stdout: '', stderr: '' };
let combinedStdout = '';
let combinedStderr = '';

Expand Down Expand Up @@ -3689,6 +3697,7 @@ class ProcessRunner extends StreamEmitter {

return {
code: lastResult.code,
exitCode: lastResult.code,
stdout: combinedStdout,
stderr: combinedStderr,
async text() {
Expand All @@ -3715,7 +3724,7 @@ class ProcessRunner extends StreamEmitter {
} else if (subshell.command.type === 'simple') {
result = await this._runSimpleCommand(subshell.command);
} else {
result = { code: 0, stdout: '', stderr: '' };
result = { code: 0, exitCode: 0, stdout: '', stderr: '' };
}

return result;
Expand Down
50 changes: 50 additions & 0 deletions tests/exitcode-alias.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { test, expect, describe, beforeEach } from 'bun:test';
import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup
import { $, shell } from '../src/$.mjs';

describe('exitCode alias for code', () => {
beforeEach(() => {
// Reset all shell settings before each test
shell.errexit(false);
shell.verbose(false);
shell.xtrace(false);
shell.pipefail(false);
shell.nounset(false);
});

test('should provide exitCode as alias for code property', async () => {
const result = await $`exit 0`;
expect(result.code).toBe(0);
expect(result.exitCode).toBe(0);
expect(result.code).toBe(result.exitCode);
});

test('should have matching exitCode for non-zero exit codes', async () => {
const result = await $`exit 42`;
expect(result.code).toBe(42);
expect(result.exitCode).toBe(42);
expect(result.code).toBe(result.exitCode);
});

test('should have matching exitCode for successful commands', async () => {
const result = await $`echo "hello"`;
expect(result.code).toBe(0);
expect(result.exitCode).toBe(0);
expect(result.code).toBe(result.exitCode);
expect(result.stdout.trim()).toBe('hello');
});

test('should maintain exitCode alias in pipeline operations', async () => {
const result = await $`echo "test" | grep "test"`;
expect(result.code).toBe(0);
expect(result.exitCode).toBe(0);
expect(result.code).toBe(result.exitCode);
});

test('should maintain exitCode alias for failed commands', async () => {
const result = await $`exit 42`;
expect(result.code).toBe(42);
expect(result.exitCode).toBe(42);
expect(result.code).toBe(result.exitCode);
});
});