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