Skip to content

Commit 86185b4

Browse files
bojavoutommy-mitchellnovemberborn
authored
Add filterNodeArgumentsForWorkerThreads option
This filter function can be used to remove node arguments that may be applied to the main process, but cannot be used to start worker threads. It can only be configured in a JavaScript configuration file. It does not apply when using child processes. Co-authored-by: Tommy <[email protected]> Co-authored-by: Mark Wubben <[email protected]>
1 parent b15df53 commit 86185b4

File tree

16 files changed

+141
-0
lines changed

16 files changed

+141
-0
lines changed

docs/06-configuration.md

+16
Original file line numberDiff line numberDiff line change
@@ -337,3 +337,19 @@ These may also export a function which is then invoked, and can receive argument
337337
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.
338338

339339
[CLI]: ./05-command-line.md
340+
341+
## Node arguments filter for worker threads
342+
343+
In a config file only, `filterNodeArgumentsForWorkerThreads` may provide a function used for filtering `nodeArguments` sent to worker threads. This enables excluding arguments that throw if sent to a thread. The filter is ignored by worker processes.
344+
345+
`ava.config.js`:
346+
```js
347+
const processOnly = new Set([
348+
'--allow-natives-syntax',
349+
'--expose-gc'
350+
]);
351+
352+
export default {
353+
filterNodeArgumentsForWorkerThreads: argument => !processOnly.has(argument)
354+
}
355+
```

lib/cli.js

+6
Original file line numberDiff line numberDiff line change
@@ -388,9 +388,15 @@ export default async function loadCli() { // eslint-disable-line complexity
388388
exit(error.message);
389389
}
390390

391+
const workerThreads = combined.workerThreads !== false;
392+
391393
let nodeArguments;
392394
try {
393395
nodeArguments = normalizeNodeArguments(conf.nodeArguments, argv['node-arguments']);
396+
if (workerThreads && 'filterNodeArgumentsForWorkerThreads' in conf) {
397+
const {filterNodeArgumentsForWorkerThreads: filter} = conf;
398+
nodeArguments = nodeArguments.filter(argument => filter(argument));
399+
}
394400
} catch (error) {
395401
exit(error.message);
396402
}

lib/load-config.js

+7
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,13 @@ export async function loadConfig({configFile, resolveFrom = process.cwd(), defau
157157
...defaults, nonSemVerExperiments: {}, ...fileConf, ...packageConf, projectDir, configFile,
158158
};
159159

160+
if (
161+
'filterNodeArgumentsForWorkerThreads' in config
162+
&& typeof config.filterNodeArgumentsForWorkerThreads !== 'function'
163+
) {
164+
throw new Error(`filterNodeArgumentsForWorkerThreads from ${fileForErrorMessage} must be a function`);
165+
}
166+
160167
const {nonSemVerExperiments: experiments} = config;
161168
if (!isPlainObject(experiments)) {
162169
throw new Error(`nonSemVerExperiments from ${fileForErrorMessage} must be an object`);

test-tap/api.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import fs from 'node:fs';
22
import path from 'node:path';
3+
import process from 'node:process';
34
import {fileURLToPath} from 'node:url';
45

56
import ciInfo from 'ci-info';
@@ -20,6 +21,7 @@ async function apiCreator(options = {}) {
2021
options.globs = normalizeGlobs({
2122
files: options.files, ignoredByWatcher: options.watchMode?.ignoreChanges, extensions: options.extensions, providers: [],
2223
});
24+
options.nodeArguments = process.execArgv;
2325
const instance = new Api(options);
2426

2527
return instance;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default {
2+
filterNodeArgumentsForWorkerThreads: [],
3+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "module"
3+
}

test/config/loader.js

+2
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ test.serial('throws an error if a .js config file has no default export', notOk(
117117

118118
test.serial('throws an error if a config file contains `ava` property', notOk('contains-ava-property'));
119119

120+
test.serial('throws an error if a config file contains a non-function `filterNodeArgumentsForWorkerThreads` property', notOk('non-function'));
121+
120122
test.serial('throws an error if a config file contains a non-object `nonSemVerExperiments` property', notOk('non-object-experiments'));
121123

122124
test.serial('throws an error if a config file enables an unsupported experiment', notOk('unsupported-experiments'));

test/config/snapshots/loader.js.md

+12
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ Generated by [AVA](https://avajs.dev).
4040
4141
'Encountered ’ava’ property in ava.config.js; avoid wrapping the configuration'
4242

43+
## throws an error if a config file contains a non-function `filterNodeArgumentsForWorkerThreads` property
44+
45+
> error message
46+
47+
'filterNodeArgumentsForWorkerThreads from ava.config.js must be a function'
48+
4349
## throws an error if a config file contains a non-object `nonSemVerExperiments` property
4450

4551
> error message
@@ -57,3 +63,9 @@ Generated by [AVA](https://avajs.dev).
5763
> error message
5864
5965
'Conflicting configuration in ava.config.js and ava.config.cjs'
66+
67+
## throws an error if a config file contains a non-function `threadArgumentsFilter` property
68+
69+
> error message
70+
71+
'threadArgumentsFilter from ava.config.js must be a function'

test/config/snapshots/loader.js.snap

66 Bytes
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "module"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import test from 'ava';
2+
3+
test('exec arguments unfiltered', t => {
4+
t.plan(2);
5+
t.truthy(process.execArgv.includes('--throw-deprecation'));
6+
t.truthy(process.execArgv.includes('--allow-natives-syntax'));
7+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const processOnly = new Set(['--allow-natives-syntax']);
2+
3+
export default {
4+
nodeArguments: [
5+
'--throw-deprecation',
6+
'--allow-natives-syntax',
7+
],
8+
filterNodeArgumentsForWorkerThreads: argument => !processOnly.has(argument),
9+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import test from 'ava';
2+
3+
test('exec arguments filtered', t => {
4+
t.plan(2);
5+
t.truthy(process.execArgv.includes('--throw-deprecation'));
6+
t.falsy(process.execArgv.includes('--allow-natives-syntax'));
7+
});

test/node-arguments/snapshots/test.js.md

+44
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,28 @@ Generated by [AVA](https://avajs.dev).
1515
},
1616
]
1717

18+
## `filterNodeArgumentsForWorkerThreads` configuration filters arguments for worker thread
19+
20+
> tests pass
21+
22+
[
23+
{
24+
file: 'thread.js',
25+
title: 'exec arguments filtered',
26+
},
27+
]
28+
29+
## `filterNodeArgumentsForWorkerThreads` configuration ignored for worker process
30+
31+
> tests pass
32+
33+
[
34+
{
35+
file: 'process.js',
36+
title: 'exec arguments unfiltered',
37+
},
38+
]
39+
1840
## detects incomplete --node-arguments
1941

2042
> fails with message
@@ -31,3 +53,25 @@ Generated by [AVA](https://avajs.dev).
3153
title: 'works',
3254
},
3355
]
56+
57+
## `threadArgumentsFilter` configuration filters arguments for worker thread
58+
59+
> tests pass
60+
61+
[
62+
{
63+
file: 'thread.js',
64+
title: 'exec arguments filtered',
65+
},
66+
]
67+
68+
## `threadArgumentsFilter` configuration ignored for worker process
69+
70+
> tests pass
71+
72+
[
73+
{
74+
file: 'process.js',
75+
title: 'exec arguments unfiltered',
76+
},
77+
]
143 Bytes
Binary file not shown.

test/node-arguments/test.js

+20
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,26 @@ test('passed node arguments to workers', async t => {
1313
t.snapshot(result.stats.passed, 'tests pass');
1414
});
1515

16+
test('`filterNodeArgumentsForWorkerThreads` configuration filters arguments for worker thread', async t => {
17+
const options = {
18+
cwd: cwd('thread-arguments-filter'),
19+
};
20+
21+
const result = await fixture(['--config=thread-arguments-filter.config.mjs', 'thread.js'], options);
22+
23+
t.snapshot(result.stats.passed, 'tests pass');
24+
});
25+
26+
test('`filterNodeArgumentsForWorkerThreads` configuration ignored for worker process', async t => {
27+
const options = {
28+
cwd: cwd('thread-arguments-filter'),
29+
};
30+
31+
const result = await fixture(['--config=thread-arguments-filter.config.mjs', '--no-worker-threads', 'process.js'], options);
32+
33+
t.snapshot(result.stats.passed, 'tests pass');
34+
});
35+
1636
test('detects incomplete --node-arguments', async t => {
1737
const options = {
1838
cwd: cwd('node-arguments'),

0 commit comments

Comments
 (0)