33#include " node_version.h"
44#include " simdjson.h"
55
6+ #include < algorithm>
67#include < cinttypes>
78
89namespace node {
@@ -21,20 +22,67 @@ inline bool HasEqualsPrefix(std::string_view arg, std::string_view flag) {
2122 arg[flag.size ()] == ' =' ;
2223}
2324
25+ inline bool IsBareConfigFileFlag (std::string_view arg) {
26+ return arg == kConfigFileFlag || arg == kExperimentalConfigFileFlag ||
27+ arg == kDefaultConfigFileFlag ;
28+ }
29+
30+ inline bool IsConfigFileFlag (std::string_view arg) {
31+ return IsBareConfigFileFlag (arg) || HasEqualsPrefix (arg, kConfigFileFlag ) ||
32+ HasEqualsPrefix (arg, kExperimentalConfigFileFlag ) ||
33+ HasEqualsPrefix (arg, kDefaultConfigFileFlag );
34+ }
35+
36+ inline std::string DefaultConfigFileArg () {
37+ return std::string (kConfigFileFlag ) + " =" +
38+ std::string (kDefaultConfigFileName );
39+ }
40+
41+ // Returns the index of the first entry in `args` that is neither the program
42+ // name nor an option for Node.js itself. Everything from there on is the
43+ // script and its arguments, or follows `--`, so it must not be read as a
44+ // config file flag.
45+ size_t GetNodeOptionsEnd (const std::vector<std::string>& args) {
46+ // The bare flags take no value. Spell them out the way GetDataFromArgs()
47+ // does before the real parse, otherwise the parser would consume the next
48+ // argument as the path.
49+ std::vector<std::string> remaining;
50+ remaining.reserve (args.size ());
51+ for (const std::string& arg : args) {
52+ remaining.push_back (IsBareConfigFileFlag (arg) ? DefaultConfigFileArg ()
53+ : arg);
54+ }
55+
56+ // Parsing into throwaway options stops exactly where the real parse will.
57+ // Any errors are reported by the real parse later on.
58+ PerProcessOptions options;
59+ std::vector<std::string> v8_args;
60+ std::vector<std::string> errors;
61+ options_parser::Parse (
62+ &remaining, nullptr , &v8_args, &options, kDisallowedInEnvvar , &errors);
63+
64+ // `remaining` is left with the program name and the unparsed arguments.
65+ return args.size () - remaining.size () + 1 ;
66+ }
67+
2468std::optional<std::string_view> ConfigReader::GetDataFromArgs (
2569 std::vector<std::string>* args) {
2670 std::optional<std::string_view> result;
2771 invalid_default_config_file_argument_ = false ;
2872
29- for (size_t i = 0 ; i < args->size (); ++i) {
73+ // Only pay for the extra parse when a config file flag might be present.
74+ if (args->empty () || std::ranges::none_of (*args, IsConfigFileFlag)) {
75+ return result;
76+ }
77+
78+ const size_t node_options_end = GetNodeOptionsEnd (*args);
79+ for (size_t i = 1 ; i < node_options_end; ++i) {
3080 std::string& arg = (*args)[i];
3181
32- if (arg == kConfigFileFlag || arg == kExperimentalConfigFileFlag ||
33- arg == kDefaultConfigFileFlag ) {
82+ if (IsBareConfigFileFlag (arg)) {
3483 // --config-file, --experimental-config-file or
3584 // --experimental-default-config-file
36- arg = std::string (kConfigFileFlag ) + " =" +
37- std::string (kDefaultConfigFileName );
85+ arg = DefaultConfigFileArg ();
3886 result = kDefaultConfigFileName ;
3987 } else if (HasEqualsPrefix (arg, kConfigFileFlag ) ||
4088 HasEqualsPrefix (arg, kExperimentalConfigFileFlag )) {
0 commit comments