@@ -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