Skip to content

Commit 6fe7e51

Browse files
authored
Fix default value of stdin with $ (#550)
1 parent 881fbad commit 6fe7e51

File tree

8 files changed

+67
-9
lines changed

8 files changed

+67
-9
lines changed

index.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export type CommonOptions<EncodingType> = {
2727
2828
If you `$ npm install foo`, you can then `execa('foo')`.
2929
30-
@default `true` with `$`/`$.sync`, `false` otherwise
30+
@default `true` with `$`, `false` otherwise
3131
*/
3232
readonly preferLocal?: boolean;
3333

@@ -63,7 +63,7 @@ export type CommonOptions<EncodingType> = {
6363
/**
6464
Same options as [`stdio`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio).
6565
66-
@default 'pipe'
66+
@default `inherit` with `$`, `pipe` otherwise
6767
*/
6868
readonly stdin?: StdioOption;
6969

index.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,14 +232,24 @@ export function execaSync(file, args, options) {
232232
};
233233
}
234234

235+
const normalizeScriptStdin = ({input, inputFile, stdio}) => input === undefined && inputFile === undefined && stdio === undefined
236+
? {stdin: 'inherit'}
237+
: {};
238+
239+
const normalizeScriptOptions = (options = {}) => ({
240+
preferLocal: true,
241+
...normalizeScriptStdin(options),
242+
...options,
243+
});
244+
235245
function create$(options) {
236246
function $(templatesOrOptions, ...expressions) {
237247
if (!Array.isArray(templatesOrOptions)) {
238248
return create$({...options, ...templatesOrOptions});
239249
}
240250

241251
const [file, ...args] = parseTemplates(templatesOrOptions, expressions);
242-
return execa(file, args, options);
252+
return execa(file, args, normalizeScriptOptions(options));
243253
}
244254

245255
$.sync = (templates, ...expressions) => {
@@ -248,13 +258,13 @@ function create$(options) {
248258
}
249259

250260
const [file, ...args] = parseTemplates(templates, expressions);
251-
return execaSync(file, args, options);
261+
return execaSync(file, args, normalizeScriptOptions(options));
252262
};
253263

254264
return $;
255265
}
256266

257-
export const $ = create$({preferLocal: true});
267+
export const $ = create$();
258268

259269
export function execaCommand(command, options) {
260270
const [file, ...args] = parseCommand(command);

readme.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ Kill the spawned process when the parent process exits unless either:
467467
#### preferLocal
468468

469469
Type: `boolean`\
470-
Default: `true` with [`$`](#command)/[`$.sync`](#synccommand), `false` otherwise
470+
Default: `true` with [`$`](#command), `false` otherwise
471471

472472
Prefer locally installed binaries when looking for a binary to execute.\
473473
If you `$ npm install foo`, you can then `execa('foo')`.
@@ -521,7 +521,7 @@ If the input is not a file, use the [`input` option](#input) instead.
521521
#### stdin
522522

523523
Type: `string | number | Stream | undefined`\
524-
Default: `pipe`
524+
Default: `inherit` with [`$`](#command), `pipe` otherwise
525525

526526
Same options as [`stdio`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio).
527527

test/command.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {inspect} from 'node:util';
22
import test from 'ava';
3+
import {isStream} from 'is-stream';
34
import {execa, execaSync, execaCommand, execaCommandSync, $} from '../index.js';
45
import {setFixtureDir} from './helpers/fixtures-dir.js';
56

@@ -273,3 +274,17 @@ test('[ $`noop.js` ]', invalidExpression, [$`noop.js`], 'Unexpected "object" in
273274

274275
test('$({stdio: \'inherit\'}).sync`noop.js`', invalidExpression, $({stdio: 'inherit'}).sync`noop.js`, 'Unexpected "undefined" stdout in template expression');
275276
test('[ $({stdio: \'inherit\'}).sync`noop.js` ]', invalidExpression, [$({stdio: 'inherit'}).sync`noop.js`], 'Unexpected "undefined" stdout in template expression');
277+
278+
test('$ stdin defaults to "inherit"', async t => {
279+
const {stdout} = await $({input: 'foo'})`stdin-script.js`;
280+
t.is(stdout, 'foo');
281+
});
282+
283+
test('$.sync stdin defaults to "inherit"', t => {
284+
const {stdout} = $({input: 'foo'}).sync`stdin-script.js`;
285+
t.is(stdout, 'foo');
286+
});
287+
288+
test('$ stdin has no default value when stdio is set', t => {
289+
t.true(isStream($({stdio: 'pipe'})`noop.js`.stdin));
290+
});

test/fixtures/stdin-script.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env node
2+
import {$} from '../../index.js';
3+
import {FIXTURES_DIR} from '../helpers/fixtures-dir.js';
4+
5+
await $({stdout: 'inherit'})`node ${`${FIXTURES_DIR}/stdin.js`}`;

test/helpers/fixtures-dir.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {fileURLToPath} from 'node:url';
44
import pathKey from 'path-key';
55

66
export const PATH_KEY = pathKey();
7-
const FIXTURES_DIR = fileURLToPath(new URL('../fixtures', import.meta.url));
7+
export const FIXTURES_DIR = fileURLToPath(new URL('../fixtures', import.meta.url));
88

99
// Add the fixtures directory to PATH so fixtures can be executed without adding
1010
// `node`. This is only meant to make writing tests simpler.

test/stream.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import test from 'ava';
66
import getStream from 'get-stream';
77
import {pEvent} from 'p-event';
88
import tempfile from 'tempfile';
9-
import {execa, execaSync} from '../index.js';
9+
import {execa, execaSync, $} from '../index.js';
1010
import {setFixtureDir} from './helpers/fixtures-dir.js';
1111

1212
setFixtureDir();
@@ -71,13 +71,25 @@ test('input can be a Stream', async t => {
7171
t.is(stdout, 'howdy');
7272
});
7373

74+
test('input option can be used with $', async t => {
75+
const {stdout} = await $({input: 'foobar'})`stdin.js`;
76+
t.is(stdout, 'foobar');
77+
});
78+
7479
test('inputFile can be set', async t => {
7580
const inputFile = tempfile();
7681
fs.writeFileSync(inputFile, 'howdy');
7782
const {stdout} = await execa('stdin.js', {inputFile});
7883
t.is(stdout, 'howdy');
7984
});
8085

86+
test('inputFile can be set with $', async t => {
87+
const inputFile = tempfile();
88+
fs.writeFileSync(inputFile, 'howdy');
89+
const {stdout} = await $({inputFile})`stdin.js`;
90+
t.is(stdout, 'howdy');
91+
});
92+
8193
test('inputFile and input cannot be both set', t => {
8294
t.throws(() => execa('stdin.js', {inputFile: '', input: ''}), {
8395
message: /cannot be both set/,
@@ -96,6 +108,11 @@ test('input option can be a String - sync', t => {
96108
t.is(stdout, 'foobar');
97109
});
98110

111+
test('input option can be used with $.sync', t => {
112+
const {stdout} = $({input: 'foobar'}).sync`stdin.js`;
113+
t.is(stdout, 'foobar');
114+
});
115+
99116
test('input option can be a Buffer - sync', t => {
100117
const {stdout} = execaSync('stdin.js', {input: Buffer.from('testing12', 'utf8')});
101118
t.is(stdout, 'testing12');
@@ -125,6 +142,13 @@ test('inputFile can be set - sync', t => {
125142
t.is(stdout, 'howdy');
126143
});
127144

145+
test('inputFile option can be used with $.sync', t => {
146+
const inputFile = tempfile();
147+
fs.writeFileSync(inputFile, 'howdy');
148+
const {stdout} = $({inputFile}).sync`stdin.js`;
149+
t.is(stdout, 'howdy');
150+
});
151+
128152
test('inputFile and input cannot be both set - sync', t => {
129153
t.throws(() => execaSync('stdin.js', {inputFile: '', input: ''}), {
130154
message: /cannot be both set/,

test/test.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ test('preferLocal: undefined with $', async t => {
100100
await t.notThrowsAsync($({env: getPathWithoutLocalDir()})`ava --version`);
101101
});
102102

103+
test('preferLocal: undefined with $.sync', t => {
104+
t.notThrows(() => $({env: getPathWithoutLocalDir()}).sync`ava --version`);
105+
});
106+
103107
test('localDir option', async t => {
104108
const command = process.platform === 'win32' ? 'echo %PATH%' : 'echo $PATH';
105109
const {stdout} = await execa(command, {shell: true, preferLocal: true, localDir: '/test'});

0 commit comments

Comments
 (0)