Skip to content

Commit b9277a0

Browse files
marco-ippolitoaduh95
authored andcommitted
src: add watch config namespace
PR-URL: #60178 Reviewed-By: Pietro Marchini <[email protected]> Reviewed-By: Chemi Atlow <[email protected]>
1 parent fbc8b7b commit b9277a0

File tree

6 files changed

+130
-11
lines changed

6 files changed

+130
-11
lines changed

doc/api/cli.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,9 @@ in the `$schema` must be replaced with the version of Node.js you are using.
950950
},
951951
"testRunner": {
952952
"test-isolation": "process"
953+
},
954+
"watch": {
955+
"watch-preserve-output": true
953956
}
954957
}
955958
```

doc/node-config-schema.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,35 @@
725725
"type": "boolean"
726726
}
727727
}
728+
},
729+
"watch": {
730+
"type": "object",
731+
"additionalProperties": false,
732+
"properties": {
733+
"watch": {
734+
"type": "boolean"
735+
},
736+
"watch-kill-signal": {
737+
"type": "string"
738+
},
739+
"watch-path": {
740+
"oneOf": [
741+
{
742+
"type": "string"
743+
},
744+
{
745+
"items": {
746+
"type": "string",
747+
"minItems": 1
748+
},
749+
"type": "array"
750+
}
751+
]
752+
},
753+
"watch-preserve-output": {
754+
"type": "boolean"
755+
}
756+
}
728757
}
729758
},
730759
"type": "object"

lib/internal/main/watch_mode.js

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22
const {
33
ArrayPrototypeForEach,
4+
ArrayPrototypeIncludes,
45
ArrayPrototypeJoin,
56
ArrayPrototypeMap,
67
ArrayPrototypePush,
@@ -17,7 +18,7 @@ const {
1718
triggerUncaughtException,
1819
exitCodes: { kNoFailure },
1920
} = internalBinding('errors');
20-
const { getOptionValue } = require('internal/options');
21+
const { getOptionValue, getOptionsAsFlagsFromBinding } = require('internal/options');
2122
const { FilesWatcher } = require('internal/watch_mode/files_watcher');
2223
const { green, blue, red, white, clear } = require('internal/util/colors');
2324
const { convertToValidSignal } = require('internal/util');
@@ -40,14 +41,14 @@ const kCommand = ArrayPrototypeSlice(process.argv, 1);
4041
const kCommandStr = inspect(ArrayPrototypeJoin(kCommand, ' '));
4142

4243
const argsWithoutWatchOptions = [];
43-
44-
for (let i = 0; i < process.execArgv.length; i++) {
45-
const arg = process.execArgv[i];
44+
const argsFromBinding = getOptionsAsFlagsFromBinding();
45+
for (let i = 0; i < argsFromBinding.length; i++) {
46+
const arg = argsFromBinding[i];
4647
if (StringPrototypeStartsWith(arg, '--watch=')) {
4748
continue;
4849
}
4950
if (arg === '--watch') {
50-
const nextArg = process.execArgv[i + 1];
51+
const nextArg = argsFromBinding[i + 1];
5152
if (nextArg && nextArg[0] !== '-') {
5253
// If `--watch` doesn't include `=` and the next
5354
// argument is not a flag then it is interpreted as
@@ -66,6 +67,16 @@ for (let i = 0; i < process.execArgv.length; i++) {
6667
}
6768
continue;
6869
}
70+
if (StringPrototypeStartsWith(arg, '--experimental-config-file')) {
71+
if (!ArrayPrototypeIncludes(arg, '=')) {
72+
// Skip the flag and the next argument (the config file path)
73+
i++;
74+
}
75+
continue;
76+
}
77+
if (arg === '--experimental-default-config-file') {
78+
continue;
79+
}
6980
ArrayPrototypePush(argsWithoutWatchOptions, arg);
7081
}
7182

src/node_options.cc

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ void EnvironmentOptions::CheckOptions(std::vector<std::string>* errors,
249249
} else if (test_runner_force_exit) {
250250
errors->push_back("either --watch or --test-force-exit "
251251
"can be used, not both");
252-
} else if (!test_runner && (argv->size() < 1 || (*argv)[1].empty())) {
252+
} else if (!test_runner && watch_mode_paths.empty() && argv->size() < 1) {
253253
errors->push_back("--watch requires specifying a file");
254254
}
255255

@@ -1011,20 +1011,26 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
10111011
AddOption("--watch",
10121012
"run in watch mode",
10131013
&EnvironmentOptions::watch_mode,
1014-
kAllowedInEnvvar);
1014+
kAllowedInEnvvar,
1015+
false,
1016+
OptionNamespaces::kWatchNamespace);
10151017
AddOption("--watch-path",
10161018
"path to watch",
10171019
&EnvironmentOptions::watch_mode_paths,
1018-
kAllowedInEnvvar);
1020+
kAllowedInEnvvar,
1021+
OptionNamespaces::kWatchNamespace);
10191022
AddOption("--watch-kill-signal",
10201023
"kill signal to send to the process on watch mode restarts"
10211024
"(default: SIGTERM)",
10221025
&EnvironmentOptions::watch_mode_kill_signal,
1023-
kAllowedInEnvvar);
1026+
kAllowedInEnvvar,
1027+
OptionNamespaces::kWatchNamespace);
10241028
AddOption("--watch-preserve-output",
10251029
"preserve outputs on watch mode restart",
10261030
&EnvironmentOptions::watch_mode_preserve_output,
1027-
kAllowedInEnvvar);
1031+
kAllowedInEnvvar,
1032+
false,
1033+
OptionNamespaces::kWatchNamespace);
10281034
Implies("--watch-path", "--watch");
10291035
AddOption("--check",
10301036
"syntax check script without executing",

src/node_options.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,8 @@ std::vector<std::string> MapAvailableNamespaces();
412412
// Define all namespace entries
413413
#define OPTION_NAMESPACE_LIST(V) \
414414
V(kNoNamespace, "") \
415-
V(kTestRunnerNamespace, "testRunner")
415+
V(kTestRunnerNamespace, "testRunner") \
416+
V(kWatchNamespace, "watch")
416417

417418
enum class OptionNamespaces {
418419
#define V(name, _) name,

test/sequential/test-watch-mode.mjs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,4 +791,73 @@ process.on('message', (message) => {
791791
`Completed running ${inspect(file)}. Waiting for file changes before restarting...`,
792792
]);
793793
});
794+
795+
it('should watch changes to a file from config file', async () => {
796+
const file = createTmpFile();
797+
const configFile = createTmpFile(JSON.stringify({ watch: { 'watch': true } }), '.json');
798+
const { stderr, stdout } = await runWriteSucceed({
799+
file, watchedFile: file, args: ['--experimental-config-file', configFile, file], options: {
800+
timeout: 10000
801+
}
802+
});
803+
804+
assert.strictEqual(stderr, '');
805+
assert.deepStrictEqual(stdout, [
806+
'running',
807+
`Completed running ${inspect(file)}. Waiting for file changes before restarting...`,
808+
`Restarting ${inspect(file)}`,
809+
'running',
810+
`Completed running ${inspect(file)}. Waiting for file changes before restarting...`,
811+
]);
812+
});
813+
814+
it('should watch changes to a file with watch-path from config file', {
815+
skip: !supportsRecursive,
816+
}, async () => {
817+
const dir = tmpdir.resolve('subdir4');
818+
mkdirSync(dir);
819+
const file = createTmpFile();
820+
const watchedFile = createTmpFile('', '.js', dir);
821+
const configFile = createTmpFile(JSON.stringify({ watch: { 'watch-path': [dir] } }), '.json', dir);
822+
823+
const args = ['--experimental-config-file', configFile, file];
824+
const { stderr, stdout } = await runWriteSucceed({ file, watchedFile, args });
825+
826+
assert.strictEqual(stderr, '');
827+
assert.deepStrictEqual(stdout, [
828+
'running',
829+
`Completed running ${inspect(file)}. Waiting for file changes before restarting...`,
830+
`Restarting ${inspect(file)}`,
831+
'running',
832+
`Completed running ${inspect(file)}. Waiting for file changes before restarting...`,
833+
]);
834+
assert.strictEqual(stderr, '');
835+
});
836+
837+
it('should watch changes to a file from default config file', async () => {
838+
const dir = tmpdir.resolve('subdir5');
839+
mkdirSync(dir);
840+
841+
const file = createTmpFile('console.log("running");', '.js', dir);
842+
writeFileSync(path.join(dir, 'node.config.json'), JSON.stringify({ watch: { 'watch': true } }));
843+
844+
const { stderr, stdout } = await runWriteSucceed({
845+
file,
846+
watchedFile: file,
847+
args: ['--experimental-default-config-file', file],
848+
options: {
849+
timeout: 10000,
850+
cwd: dir
851+
}
852+
});
853+
854+
assert.strictEqual(stderr, '');
855+
assert.deepStrictEqual(stdout, [
856+
'running',
857+
`Completed running ${inspect(file)}. Waiting for file changes before restarting...`,
858+
`Restarting ${inspect(file)}`,
859+
'running',
860+
`Completed running ${inspect(file)}. Waiting for file changes before restarting...`,
861+
]);
862+
});
794863
});

0 commit comments

Comments
 (0)