Skip to content

Commit 037cc33

Browse files
committed
Simplify implementation
* Combine values without overwriting duplicates * Use Node.js to parse the argv string Also add a bit more context in the documentation.
1 parent 18b7074 commit 037cc33

11 files changed

+40
-74
lines changed

docs/05-command-line.md

+17-3
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ Options:
2929
--fail-fast Stop after first test failure [boolean]
3030
--match, -m Only run tests with matching title (Can be repeated)
3131
[string]
32-
--node-arguments Configure Node.js arguments used to launch worker
33-
processes (be sure to surround the value by double
34-
quotes) [string]
32+
--node-arguments Additional Node.js arguments for launching worker
33+
processes (specify as a single string; only use
34+
trusted values) [string]
3535
--serial, -s Run tests serially [boolean]
3636
--tap, -t Generate TAP output [boolean]
3737
--timeout, -T Set global timeout (milliseconds or human-readable,
@@ -181,3 +181,17 @@ $ npx ava --tap | npx tap-nyan
181181
<img src="../media/tap-reporter.png" width="420">
182182

183183
Please note that the TAP reporter is unavailable when using [watch mode](./recipes/watch-mode.md).
184+
185+
## Node arguments
186+
187+
The `--node-arguments` argument may be used to specify additional arguments for launching worker processes. These are combined with the `nodeArguments` configuration and any arguments passed to the `node` binary when starting AVA.
188+
189+
**Only pass trusted values.**
190+
191+
Specify the arguments as a single string:
192+
193+
```console
194+
npx ava --node-arguments="--throw-deprecation --zero-fill-buffers"
195+
```
196+
197+
**Only pass trusted values.**

docs/06-configuration.md

+4
Original file line numberDiff line numberDiff line change
@@ -224,4 +224,8 @@ export default {
224224
};
225225
```
226226

227+
## Node arguments
228+
229+
The `nodeArguments` configuration may be used to specify additional arguments for launching worker processes. These are combined with `--node-arguments` passed on the CLI and any arguments passed to the `node` binary when starting AVA.
230+
227231
[CLI]: ./05-command-line.md

lib/api.js

+1-14
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ const arrify = require('arrify');
1010
const ms = require('ms');
1111
const chunkd = require('chunkd');
1212
const Emittery = require('emittery');
13-
const yargs = require('yargs-parser');
14-
const dargs = require('dargs');
15-
const memoize = require('lodash/memoize');
1613
const pMap = require('p-map');
1714
const tempDir = require('temp-dir');
1815
const globs = require('./globs');
@@ -41,16 +38,6 @@ function getFilePathPrefix(files) {
4138
return commonPathPrefix(files);
4239
}
4340

44-
const _parseProcessArgs = memoize(() => {
45-
// Do not reference this, function is called as static
46-
return yargs(process.execArgv, {
47-
configuration: {
48-
'camel-case-expansion': false,
49-
'dot-notation': false
50-
}
51-
});
52-
});
53-
5441
class Api extends Emittery {
5542
constructor(options) {
5643
super();
@@ -232,7 +219,7 @@ class Api extends Emittery {
232219
options.updateSnapshots = true;
233220
}
234221

235-
const worker = fork(file, options, dargs({..._parseProcessArgs(), ...apiOptions.nodeArguments}));
222+
const worker = fork(file, options, apiOptions.nodeArguments);
236223
runStatus.observeWorker(worker, file);
237224

238225
pendingWorkers.add(worker);

lib/cli.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const FLAGS = {
3737
},
3838
'node-arguments': {
3939
coerce: coerceLastValue,
40-
description: 'Configure Node.js arguments used to launch worker processes (be sure to surround the value by double quotes)',
40+
description: 'Additional Node.js arguments for launching worker processes (specify as a single string; only use trusted values)',
4141
type: 'string'
4242
},
4343
serial: {
@@ -311,7 +311,7 @@ exports.run = async () => { // eslint-disable-line complexity
311311

312312
let nodeArguments;
313313
try {
314-
nodeArguments = normalizeNodeArguments(conf.nodeArguments, argv['node-arguments']);
314+
nodeArguments = await normalizeNodeArguments(conf.nodeArguments, argv['node-arguments']);
315315
} catch (error) {
316316
exit(error.message);
317317
}

lib/fork.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const AVA_PATH = path.resolve(__dirname, '..');
1414

1515
const workerPath = require.resolve('./worker/subprocess');
1616

17-
module.exports = (file, opts, execArgv) => {
17+
module.exports = (file, opts, execArgv = process.execArgv) => {
1818
let finished = false;
1919

2020
const emitter = new Emittery();
@@ -34,7 +34,7 @@ module.exports = (file, opts, execArgv) => {
3434
cwd: opts.projectDir,
3535
silent: true,
3636
env: {NODE_ENV: 'test', ...process.env, ...opts.environmentVariables, AVA_PATH},
37-
execArgv: execArgv || process.execArgv
37+
execArgv
3838
});
3939

4040
subprocess.stdout.on('data', chunk => {

lib/node-arguments.js

+9-22
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,16 @@
11
'use strict';
2+
const execa = require('execa');
23

3-
const yargs = require('yargs-parser');
4-
5-
const configuration = {
6-
'camel-case-expansion': false,
7-
'dot-notation': false
8-
};
9-
10-
// See https://github.com/sindresorhus/meow/issues/128
11-
function fixCliParams(cliStr) {
12-
// Slice surrounding ' and "
13-
if (cliStr[0] === cliStr[cliStr.length - 1] && '"\''.includes(cliStr[0])) {
14-
return cliStr.slice(1, -1);
4+
async function normalizeNodeArguments(fromConf = [], fromArgv = '') {
5+
let parsedArgv = [];
6+
if (fromArgv !== '') {
7+
// Use Node.js itself to parse the arguments. This may lead to arbitrary code execution, but since this is only
8+
// applied to arguments passed when invoking AVA on the command line this is not considered a vulnerability.
9+
const {stdout} = await execa.command(`${process.execPath} -pe\\ 'JSON.stringify(process.execArgv)'\\ ${fromArgv.replace(/ /g, '\\ ')}`, {shell: true});
10+
parsedArgv = JSON.parse(stdout).slice(2);
1511
}
1612

17-
return cliStr;
18-
}
19-
20-
function normalizeNodeArguments(confParams = [], cliParams = '') {
21-
const {_, '--': __, ...params} = {
22-
...yargs(confParams, {configuration}),
23-
...yargs(fixCliParams(cliParams), {configuration})
24-
};
25-
26-
return params;
13+
return [...process.execArgv, ...fromConf, ...parsedArgv];
2714
}
2815

2916
module.exports = normalizeNodeArguments;

package-lock.json

-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-3
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@
7373
"concordance": "^4.0.0",
7474
"convert-source-map": "^1.7.0",
7575
"currently-unhandled": "^0.4.1",
76-
"dargs": "^7.0.0",
7776
"debug": "^4.1.1",
7877
"del": "^5.1.0",
7978
"emittery": "^0.5.1",
@@ -108,8 +107,7 @@
108107
"trim-off-newlines": "^1.0.1",
109108
"update-notifier": "^4.0.0",
110109
"write-file-atomic": "^3.0.1",
111-
"yargs": "^15.1.0",
112-
"yargs-parser": "^16.1.0"
110+
"yargs": "^15.1.0"
113111
},
114112
"devDependencies": {
115113
"@ava/babel": "^0.7.0",

test/api.js

-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ const {test} = require('tap');
88
const Api = require('../lib/api');
99
const babelManager = require('../lib/babel-manager');
1010
const {normalizeGlobs} = require('../lib/globs');
11-
const nodeArguments = require('../lib/node-arguments');
1211

1312
const ROOT_DIR = path.join(__dirname, '..');
1413

@@ -23,7 +22,6 @@ function apiCreator(options = {}) {
2322
options.extensions = options.extensions || ['js'];
2423
options.experiments = {};
2524
options.globs = normalizeGlobs({files: options.files, ignoredByWatcher: options.ignoredByWatcher, extensions: options.extensions});
26-
options.nodeArguments = options.nodeArguments || {};
2725
const instance = new Api(options);
2826

2927
return instance;

test/helper/report.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,7 @@ const run = (type, reporter, match = []) => {
8989
concurrency: 1,
9090
updateSnapshots: false,
9191
snapshotDir: false,
92-
chalkOptions: {level: 1},
93-
nodeArguments: {}
92+
chalkOptions: {level: 1}
9493
};
9594
let pattern = '*.js';
9695

test/node-arguments.js

+3-19
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,10 @@
33
const {test} = require('tap');
44
const normalizeNodeArguments = require('../lib/node-arguments');
55

6-
test('normalizes multiple node arguments from cli', t => {
7-
t.deepEqual(normalizeNodeArguments([], '--a --b --c'), {a: true, b: true, c: true});
8-
t.end();
9-
});
10-
11-
test('normalizes multiple node arguments from config', t => {
12-
t.deepEqual(normalizeNodeArguments(['--arg1', '--b'], ''), {arg1: true, b: true});
13-
t.end();
14-
});
15-
16-
test('normalizes node arguments from config and cli', t => {
6+
test('combines arguments', async t => {
177
t.deepEqual(
18-
normalizeNodeArguments(['--arg1', '--b=2'], '--arg2 --b=12'),
19-
{arg1: true, arg2: true, b: 12}
8+
await normalizeNodeArguments(['--require setup.js'], '--throw-deprecation --zero-fill-buffers'),
9+
[...process.execArgv, '--require setup.js', '--throw-deprecation', '--zero-fill-buffers']
2010
);
2111
t.end();
2212
});
23-
24-
test('normalizes single node arguments from cli', t => {
25-
t.deepEqual(normalizeNodeArguments([], '--test-flag'), {'test-flag': true});
26-
t.deepEqual(normalizeNodeArguments([], '--test-flag="a & b"'), {'test-flag': 'a & b'});
27-
t.end();
28-
});

0 commit comments

Comments
 (0)