@@ -1864,6 +1864,117 @@ void GetNamespaceOptionsInputType(const FunctionCallbackInfo<Value>& args) {
1864
1864
args.GetReturnValue ().Set (namespaces_map);
1865
1865
}
1866
1866
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
+
1867
1978
void Initialize (Local<Object> target,
1868
1979
Local<Value> unused,
1869
1980
Local<Context> context,
@@ -1874,6 +1985,8 @@ void Initialize(Local<Object> target,
1874
1985
context, target, " getCLIOptionsValues" , GetCLIOptionsValues);
1875
1986
SetMethodNoSideEffect (
1876
1987
context, target, " getCLIOptionsInfo" , GetCLIOptionsInfo);
1988
+ SetMethodNoSideEffect (
1989
+ context, target, " getOptionsAsFlags" , GetOptionsAsFlags);
1877
1990
SetMethodNoSideEffect (
1878
1991
context, target, " getEmbedderOptions" , GetEmbedderOptions);
1879
1992
SetMethodNoSideEffect (
@@ -1906,6 +2019,7 @@ void Initialize(Local<Object> target,
1906
2019
void RegisterExternalReferences (ExternalReferenceRegistry* registry) {
1907
2020
registry->Register (GetCLIOptionsValues);
1908
2021
registry->Register (GetCLIOptionsInfo);
2022
+ registry->Register (GetOptionsAsFlags);
1909
2023
registry->Register (GetEmbedderOptions);
1910
2024
registry->Register (GetEnvOptionsInputType);
1911
2025
registry->Register (GetNamespaceOptionsInputType);
0 commit comments