From acfc7f02c49d389f7e7838744d5efba5bc4a8abe Mon Sep 17 00:00:00 2001 From: ehmicky Date: Sun, 6 Feb 2022 15:49:40 +0100 Subject: [PATCH 1/6] Allow `cwd` option to be a URL --- index.d.ts | 2 +- index.test-d.ts | 1 + readme.md | 2 +- test/test.js | 15 ++++++++++++++- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/index.d.ts b/index.d.ts index fdf9de1c3..906867e04 100644 --- a/index.d.ts +++ b/index.d.ts @@ -113,7 +113,7 @@ export interface CommonOptions { @default process.cwd() */ - readonly cwd?: string; + readonly cwd?: string | URL; /** Environment key-value pairs. Extends automatically from `process.env`. Set `extendEnv` to `false` if you don't want this. diff --git a/index.test-d.ts b/index.test-d.ts index 5e06366a5..55d5e889c 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -121,6 +121,7 @@ execa('unicorns', {reject: false}); execa('unicorns', {stripFinalNewline: false}); execa('unicorns', {extendEnv: false}); execa('unicorns', {cwd: '.'}); +execa('unicorns', {cwd: new URL('.')}); // eslint-disable-next-line @typescript-eslint/naming-convention execa('unicorns', {env: {PATH: ''}}); execa('unicorns', {argv0: ''}); diff --git a/readme.md b/readme.md index a9db621b9..e15ad010b 100644 --- a/readme.md +++ b/readme.md @@ -446,7 +446,7 @@ Execa also accepts the below options which are the same as the options for [`chi #### cwd -Type: `string`\ +Type: `string | URL`\ Default: `process.cwd()` Current working directory of the child process. diff --git a/test/test.js b/test/test.js index 23449f52b..ac8fcc764 100644 --- a/test/test.js +++ b/test/test.js @@ -1,6 +1,6 @@ import path from 'node:path'; import process from 'node:process'; -import {fileURLToPath} from 'node:url'; +import {fileURLToPath, pathToFileURL} from 'node:url'; import test from 'ava'; import isRunning from 'is-running'; import getNode from 'get-node'; @@ -198,6 +198,19 @@ test('do not extend environment with `extendEnv: false`', async t => { t.deepEqual(stdout.split('\n'), ['undefined', 'bar']); }); +test('can use `options.cwd` as a string', async t => { + const cwd = '/'; + const {stdout} = await execa('node', ['-p', 'process.cwd()'], {cwd}); + t.is(stdout, cwd); +}); + +test('can use `options.cwd` as a URL', async t => { + const cwd = '/'; + const cwdUrl = pathToFileURL(cwd); + const {stdout} = await execa('node', ['-p', 'process.cwd()'], {cwd: cwdUrl}); + t.is(stdout, cwd); +}); + test('can use `options.shell: true`', async t => { const {stdout} = await execa('node test/fixtures/noop.js foo', {shell: true}); t.is(stdout, 'foo'); From 51ed65e062e8bf5bf4f044e6a4dbb10fb81202c0 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Sun, 6 Feb 2022 15:49:56 +0100 Subject: [PATCH 2/6] Allow `localDir` to be a URL --- index.d.ts | 2 +- index.test-d.ts | 3 ++- readme.md | 2 +- test/test.js | 7 +++++++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/index.d.ts b/index.d.ts index 906867e04..3f2b7ba2c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -35,7 +35,7 @@ export interface CommonOptions { @default process.cwd() */ - readonly localDir?: string; + readonly localDir?: string | URL; /** Path to the Node.js executable to use in child processes. diff --git a/index.test-d.ts b/index.test-d.ts index 55d5e889c..e8d0a0d11 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -90,6 +90,7 @@ try { execa('unicorns', {cleanup: false}); execa('unicorns', {preferLocal: false}); execa('unicorns', {localDir: '.'}); +execa('unicorns', {localDir: new URL('file:///test')}); execa('unicorns', {execPath: '/path'}); execa('unicorns', {buffer: false}); execa('unicorns', {input: ''}); @@ -121,7 +122,7 @@ execa('unicorns', {reject: false}); execa('unicorns', {stripFinalNewline: false}); execa('unicorns', {extendEnv: false}); execa('unicorns', {cwd: '.'}); -execa('unicorns', {cwd: new URL('.')}); +execa('unicorns', {cwd: new URL('file:///test')}); // eslint-disable-next-line @typescript-eslint/naming-convention execa('unicorns', {env: {PATH: ''}}); execa('unicorns', {argv0: ''}); diff --git a/readme.md b/readme.md index e15ad010b..302e0f107 100644 --- a/readme.md +++ b/readme.md @@ -357,7 +357,7 @@ If you `$ npm install foo`, you can then `execa('foo')`. #### localDir -Type: `string`\ +Type: `string | URL`\ Default: `process.cwd()` Preferred path to find locally installed binaries in (use with `preferLocal`). diff --git a/test/test.js b/test/test.js index ac8fcc764..3924fab75 100644 --- a/test/test.js +++ b/test/test.js @@ -95,6 +95,13 @@ test('localDir option', async t => { t.true(envPaths.some(envPath => envPath.endsWith('.bin'))); }); +test('localDir option can be a URL', async t => { + const command = process.platform === 'win32' ? 'echo %PATH%' : 'echo $PATH'; + const {stdout} = await execa(command, {shell: true, preferLocal: true, localDir: pathToFileURL('/test')}); + const envPaths = stdout.split(path.delimiter); + t.true(envPaths.some(envPath => envPath.endsWith('.bin'))); +}); + test('execPath option', async t => { const {path: execPath} = await getNode('6.0.0'); const {stdout} = await execa('node', ['-p', 'process.env.Path || process.env.PATH'], {preferLocal: true, execPath}); From 25550d14ec59338a318edc19bc4d021bce4d7266 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Sun, 6 Feb 2022 15:50:17 +0100 Subject: [PATCH 3/6] Add comment about Node.js version --- readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readme.md b/readme.md index 302e0f107..c1aa8ea30 100644 --- a/readme.md +++ b/readme.md @@ -362,6 +362,8 @@ Default: `process.cwd()` Preferred path to find locally installed binaries in (use with `preferLocal`). +Using a `URL` is only supported in Node.js `14.18.0`, `16.14.0` or above. + #### execPath Type: `string`\ @@ -451,6 +453,8 @@ Default: `process.cwd()` Current working directory of the child process. +Using a `URL` is only supported in Node.js `14.18.0`, `16.14.0` or above. + #### env Type: `object`\ From abb0ef9c950be296d3b7c5576e2140849c8825c1 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Sun, 6 Feb 2022 15:50:53 +0100 Subject: [PATCH 4/6] Fix old Node.js version support --- package.json | 1 + test/test.js | 29 ++++++++++++++++------------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 360439757..187138879 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "get-node": "^12.0.0", "is-running": "^2.1.0", "p-event": "^5.0.1", + "semver": "^7.3.5", "tempfile": "^4.0.0", "tsd": "^0.18.0", "xo": "^0.46.4" diff --git a/test/test.js b/test/test.js index 3924fab75..b9374d8cf 100644 --- a/test/test.js +++ b/test/test.js @@ -4,6 +4,7 @@ import {fileURLToPath, pathToFileURL} from 'node:url'; import test from 'ava'; import isRunning from 'is-running'; import getNode from 'get-node'; +import semver from 'semver'; import {execa, execaSync} from '../index.js'; process.env.PATH = fileURLToPath(new URL('./fixtures', import.meta.url)) + path.delimiter + process.env.PATH; @@ -95,13 +96,6 @@ test('localDir option', async t => { t.true(envPaths.some(envPath => envPath.endsWith('.bin'))); }); -test('localDir option can be a URL', async t => { - const command = process.platform === 'win32' ? 'echo %PATH%' : 'echo $PATH'; - const {stdout} = await execa(command, {shell: true, preferLocal: true, localDir: pathToFileURL('/test')}); - const envPaths = stdout.split(path.delimiter); - t.true(envPaths.some(envPath => envPath.endsWith('.bin'))); -}); - test('execPath option', async t => { const {path: execPath} = await getNode('6.0.0'); const {stdout} = await execa('node', ['-p', 'process.env.Path || process.env.PATH'], {preferLocal: true, execPath}); @@ -211,12 +205,21 @@ test('can use `options.cwd` as a string', async t => { t.is(stdout, cwd); }); -test('can use `options.cwd` as a URL', async t => { - const cwd = '/'; - const cwdUrl = pathToFileURL(cwd); - const {stdout} = await execa('node', ['-p', 'process.cwd()'], {cwd: cwdUrl}); - t.is(stdout, cwd); -}); +if (semver.satisfies(process.version, '^14.18.0 || >=16.4.0')) { + test('localDir option can be a URL', async t => { + const command = process.platform === 'win32' ? 'echo %PATH%' : 'echo $PATH'; + const {stdout} = await execa(command, {shell: true, preferLocal: true, localDir: pathToFileURL('/test')}); + const envPaths = stdout.split(path.delimiter); + t.true(envPaths.some(envPath => envPath.endsWith('.bin'))); + }); + + test('can use `options.cwd` as a URL', async t => { + const cwd = '/'; + const cwdUrl = pathToFileURL(cwd); + const {stdout} = await execa('node', ['-p', 'process.cwd()'], {cwd: cwdUrl}); + t.is(stdout, cwd); + }); +} test('can use `options.shell: true`', async t => { const {stdout} = await execa('node test/fixtures/noop.js foo', {shell: true}); From fecf144c843d08fcac4d112e2f8820b249474bd9 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Sun, 6 Feb 2022 15:51:36 +0100 Subject: [PATCH 5/6] Fix tests on Windows --- test/test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test.js b/test/test.js index b9374d8cf..d24607631 100644 --- a/test/test.js +++ b/test/test.js @@ -202,7 +202,7 @@ test('do not extend environment with `extendEnv: false`', async t => { test('can use `options.cwd` as a string', async t => { const cwd = '/'; const {stdout} = await execa('node', ['-p', 'process.cwd()'], {cwd}); - t.is(stdout, cwd); + t.is(path.toNamespacedPath(stdout), path.toNamespacedPath(cwd)); }); if (semver.satisfies(process.version, '^14.18.0 || >=16.4.0')) { @@ -217,7 +217,7 @@ if (semver.satisfies(process.version, '^14.18.0 || >=16.4.0')) { const cwd = '/'; const cwdUrl = pathToFileURL(cwd); const {stdout} = await execa('node', ['-p', 'process.cwd()'], {cwd: cwdUrl}); - t.is(stdout, cwd); + t.is(path.toNamespacedPath(stdout), path.toNamespacedPath(cwd)); }); } From f8fd7fb7df5707ff50628c69fe1d998f32f0180e Mon Sep 17 00:00:00 2001 From: ehmicky Date: Sun, 6 Feb 2022 19:26:37 +0100 Subject: [PATCH 6/6] Add more documentation in TypeScript --- index.d.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/index.d.ts b/index.d.ts index 3f2b7ba2c..bcf04f922 100644 --- a/index.d.ts +++ b/index.d.ts @@ -33,6 +33,8 @@ export interface CommonOptions { /** Preferred path to find locally installed binaries in (use with `preferLocal`). + Using a `URL` is only supported in Node.js `14.18.0`, `16.14.0` or above. + @default process.cwd() */ readonly localDir?: string | URL; @@ -111,6 +113,8 @@ export interface CommonOptions { /** Current working directory of the child process. + Using a `URL` is only supported in Node.js `14.18.0`, `16.14.0` or above. + @default process.cwd() */ readonly cwd?: string | URL;