@@ -1864,6 +1864,117 @@ void GetNamespaceOptionsInputType(const FunctionCallbackInfo<Value>& args) {
18641864 args.GetReturnValue ().Set (namespaces_map);
18651865}
18661866
1867+ // Return an array containing all currently active options as flag
1868+ // strings from all sources (command line, NODE_OPTIONS, config file)
1869+ void GetOptionsAsFlags (const FunctionCallbackInfo<Value>& args) {
1870+ Isolate* isolate = args.GetIsolate ();
1871+ Local<Context> context = isolate->GetCurrentContext ();
1872+ Environment* env = Environment::GetCurrent (context);
1873+
1874+ if (!env->has_run_bootstrapping_code ()) {
1875+ // No code because this is an assertion.
1876+ THROW_ERR_OPTIONS_BEFORE_BOOTSTRAPPING (
1877+ isolate, " Should not query options before bootstrapping is done" );
1878+ }
1879+ env->set_has_serialized_options (true );
1880+
1881+ Mutex::ScopedLock lock (per_process::cli_options_mutex);
1882+ IterateCLIOptionsScope s (env);
1883+
1884+ std::vector<std::string> flags;
1885+ PerProcessOptions* opts = per_process::cli_options.get ();
1886+
1887+ for (const auto & item : _ppop_instance.options_ ) {
1888+ const std::string& option_name = item.first ;
1889+ const auto & option_info = item.second ;
1890+ auto field = option_info.field ;
1891+
1892+ // TODO(pmarchini): Skip internal options for the moment as probably not
1893+ // required
1894+ if (option_name.empty () || option_name.starts_with (' [' )) {
1895+ continue ;
1896+ }
1897+
1898+ // Skip V8 options and NoOp options - only Node.js-specific options
1899+ if (option_info.type == kNoOp || option_info.type == kV8Option ) {
1900+ continue ;
1901+ }
1902+
1903+ switch (option_info.type ) {
1904+ case kBoolean : {
1905+ bool current_value = *_ppop_instance.Lookup <bool >(field, opts);
1906+ // For boolean options with default_is_true, we want the opposite logic
1907+ if (option_info.default_is_true ) {
1908+ if (!current_value) {
1909+ // If default is true and current is false, add --no-* flag
1910+ flags.push_back (" --no-" + option_name.substr (2 ));
1911+ }
1912+ } else {
1913+ if (current_value) {
1914+ // If default is false and current is true, add --flag
1915+ flags.push_back (option_name);
1916+ }
1917+ }
1918+ break ;
1919+ }
1920+ case kInteger : {
1921+ int64_t current_value = *_ppop_instance.Lookup <int64_t >(field, opts);
1922+ flags.push_back (option_name + " =" + std::to_string (current_value));
1923+ break ;
1924+ }
1925+ case kUInteger : {
1926+ uint64_t current_value = *_ppop_instance.Lookup <uint64_t >(field, opts);
1927+ flags.push_back (option_name + " =" + std::to_string (current_value));
1928+ break ;
1929+ }
1930+ case kString : {
1931+ const std::string& current_value =
1932+ *_ppop_instance.Lookup <std::string>(field, opts);
1933+ // Only include if not empty
1934+ if (!current_value.empty ()) {
1935+ flags.push_back (option_name + " =" + current_value);
1936+ }
1937+ break ;
1938+ }
1939+ case kStringList : {
1940+ const std::vector<std::string>& current_values =
1941+ *_ppop_instance.Lookup <StringVector>(field, opts);
1942+ // Add each string in the list as a separate flag
1943+ for (const std::string& value : current_values) {
1944+ flags.push_back (option_name + " =" + value);
1945+ }
1946+ break ;
1947+ }
1948+ case kHostPort : {
1949+ const HostPort& host_port =
1950+ *_ppop_instance.Lookup <HostPort>(field, opts);
1951+ // Only include if host is not empty or port is not default
1952+ if (!host_port.host ().empty () || host_port.port () != 0 ) {
1953+ std::string host_port_str = host_port.host ();
1954+ if (host_port.port () != 0 ) {
1955+ if (!host_port_str.empty ()) {
1956+ host_port_str += " :" ;
1957+ }
1958+ host_port_str += std::to_string (host_port.port ());
1959+ }
1960+ if (!host_port_str.empty ()) {
1961+ flags.push_back (option_name + " =" + host_port_str);
1962+ }
1963+ }
1964+ break ;
1965+ }
1966+ default :
1967+ // Skip unknown types
1968+ break ;
1969+ }
1970+ }
1971+
1972+ Local<Value> result;
1973+ CHECK (ToV8Value (context, flags).ToLocal (&result));
1974+
1975+ args.GetReturnValue ().Set (result);
1976+ }
1977+
18671978void Initialize (Local<Object> target,
18681979 Local<Value> unused,
18691980 Local<Context> context,
@@ -1874,6 +1985,8 @@ void Initialize(Local<Object> target,
18741985 context, target, " getCLIOptionsValues" , GetCLIOptionsValues);
18751986 SetMethodNoSideEffect (
18761987 context, target, " getCLIOptionsInfo" , GetCLIOptionsInfo);
1988+ SetMethodNoSideEffect (
1989+ context, target, " getOptionsAsFlags" , GetOptionsAsFlags);
18771990 SetMethodNoSideEffect (
18781991 context, target, " getEmbedderOptions" , GetEmbedderOptions);
18791992 SetMethodNoSideEffect (
@@ -1906,6 +2019,7 @@ void Initialize(Local<Object> target,
19062019void RegisterExternalReferences (ExternalReferenceRegistry* registry) {
19072020 registry->Register (GetCLIOptionsValues);
19082021 registry->Register (GetCLIOptionsInfo);
2022+ registry->Register (GetOptionsAsFlags);
19092023 registry->Register (GetEmbedderOptions);
19102024 registry->Register (GetEnvOptionsInputType);
19112025 registry->Register (GetNamespaceOptionsInputType);
0 commit comments